Added an optional classifier callback to markdownToHtml to classify source
found in github style triple backtick code blocks.
Added Dart classifier built on analyzer_experimental based on original dartdoc
classifier.
Added dart handler to default classifier impl.
diff --git a/pkgs/markdown/lib/markdown.dart b/pkgs/markdown/lib/markdown.dart
index ba355eb..0bcc777 100644
--- a/pkgs/markdown/lib/markdown.dart
+++ b/pkgs/markdown/lib/markdown.dart
@@ -5,7 +5,7 @@
 /// Parses text in a markdown-like format and renders to HTML.
 library markdown;
 
-//import 'classify.dart';
+import 'src/classify/dart.dart';
 
 // TODO(rnystrom): Use "package:" URL (#4968).
 part 'src/markdown/ast.dart';
@@ -13,9 +13,11 @@
 part 'src/markdown/html_renderer.dart';
 part 'src/markdown/inline_parser.dart';
 
+typedef String ClassifierFunction(String syntax, String source); 
+
 /// Converts the given string of markdown to HTML.
-String markdownToHtml(String markdown) {
-  final document = new Document();
+String markdownToHtml(String markdown, [ClassifierFunction classifier]) {
+  final document = new Document(classifier);
 
   // Replace windows line endings with unix line endings, and split.
   final lines = markdown.replaceAll('\r\n','\n').split('\n');
@@ -40,10 +42,17 @@
 /// Maintains the context needed to parse a markdown document.
 class Document {
   final Map<String, Link> refLinks;
-
-  Document()
+  final ClassifierFunction classifier;
+  
+  Document(this.classifier)
     : refLinks = <String, Link>{};
-
+  
+  String classify(String syntax, String source) {
+    if (syntax == 'dart') return classifyDart(source);
+    if (classifier == null) return source;
+    return classifier(syntax, source);
+  }
+    
   parseRefLinks(List<String> lines) {
     // This is a hideous regex. It matches:
     // [id]: http:foo.com "some title"
diff --git a/pkgs/markdown/lib/src/classify/dart.dart b/pkgs/markdown/lib/src/classify/dart.dart
new file mode 100644
index 0000000..2b67f9c
--- /dev/null
+++ b/pkgs/markdown/lib/src/classify/dart.dart
@@ -0,0 +1,173 @@
+library classify;
+
+import 'package:analyzer_experimental/src/generated/java_core.dart';
+import 'package:analyzer_experimental/src/generated/scanner.dart';
+
+class Classification {
+  static const NONE = "";
+  static const ERROR = "e";
+  static const COMMENT = "c";
+  static const IDENTIFIER = "i";
+  static const KEYWORD = "k";
+  static const OPERATOR = "o";
+  static const STRING = "s";
+  static const NUMBER = "n";
+  static const PUNCTUATION = "p";
+  static const TYPE_IDENTIFIER = "t";
+  static const SPECIAL_IDENTIFIER = "r";
+  static const ARROW_OPERATOR = "a";
+  static const STRING_INTERPOLATION = 'si';
+}
+
+String classifyDart(String src) {
+  var scanner = new StringScanner(null, src, null);
+  var token = scanner.tokenize();
+  var out = new StringBuffer();
+  var pos = 0;
+  while (token.type != TokenType.EOF) {
+    // If not a token and not whitespace assume comment. 
+    var comment = src.slice(pos, token.offset);
+    if (comment.trim().length > 0) out.add('<span class="${Classification.COMMENT}">$comment</span>');
+    else out.add(comment);
+    pos = token.end;
+    
+    var inString = (token.type == TokenType.STRING 
+        || token.type == TokenType.STRING_INTERPOLATION_EXPRESSION 
+        || token.type == TokenType.STRING_INTERPOLATION_IDENTIFIER);
+    var stringClass = inString ? ' ${Classification.STRING_INTERPOLATION}' : '';
+    var kind = classify(token);
+    out.add('<span class="$kind$stringClass">$token</span>');
+    token = token.next;
+  }
+  return out.toString();
+}
+
+Map createTokenMap() {
+  var map = new Map();
+  [ TokenType.OPEN_PAREN,
+    TokenType.CLOSE_PAREN,
+    TokenType.OPEN_CURLY_BRACKET,
+    TokenType.CLOSE_CURLY_BRACKET,
+    TokenType.OPEN_SQUARE_BRACKET,
+    TokenType.OPEN_SQUARE_BRACKET,
+    TokenType.COLON,
+    TokenType.SEMICOLON,
+    TokenType.COMMA,
+    TokenType.PERIOD,
+    TokenType.PERIOD_PERIOD
+  ].forEach((t) => map[t] = Classification.PUNCTUATION);
+  
+  [ TokenType.INT,
+    TokenType.HEXADECIMAL,
+    TokenType.DOUBLE
+  ].forEach((t) => map[t] = Classification.NUMBER);
+  
+  [ TokenType.STRING,
+    TokenType.STRING_INTERPOLATION_IDENTIFIER,
+    TokenType.STRING_INTERPOLATION_EXPRESSION,
+    TokenType.DOUBLE
+  ].forEach((t) => map[t] = Classification.STRING);
+  
+  [ TokenType.PLUS_PLUS,
+    TokenType.MINUS_MINUS,
+    TokenType.TILDE,
+    TokenType.BANG,
+    TokenType.EQ,
+    TokenType.BAR_EQ,
+    TokenType.CARET_EQ,
+    TokenType.AMPERSAND_EQ,
+    TokenType.LT_LT_EQ,
+    TokenType.GT_GT_EQ,
+    TokenType.PLUS_EQ,
+    TokenType.MINUS_EQ,
+    TokenType.STAR_EQ,
+    TokenType.SLASH_EQ,
+    TokenType.TILDE_SLASH_EQ,
+    TokenType.PERCENT_EQ,
+    TokenType.QUESTION,
+    TokenType.BAR_BAR,
+    TokenType.AMPERSAND_AMPERSAND,
+    TokenType.BAR,
+    TokenType.CARET,
+    TokenType.AMPERSAND,
+    TokenType.LT_LT,
+    TokenType.GT_GT,
+    TokenType.PLUS,
+    TokenType.MINUS,
+    TokenType.STAR,
+    TokenType.SLASH,
+    TokenType.TILDE_SLASH,
+    TokenType.PERCENT,
+    TokenType.EQ_EQ,
+    TokenType.BANG_EQ,
+    TokenType.LT,
+    TokenType.GT,
+    TokenType.LT_EQ,
+    TokenType.GT_EQ,
+    TokenType.INDEX,
+    TokenType.INDEX_EQ,
+  ].forEach((t) => map[t] = Classification.OPERATOR);
+  
+  // => is so awesome it is in a class of its own.
+  map[TokenType.FUNCTION] = Classification.ARROW_OPERATOR;
+  
+  map[TokenType.IDENTIFIER] = Classification.IDENTIFIER;
+  map[TokenType.KEYWORD] = Classification.KEYWORD;
+  map[TokenType.HASH] = Classification.KEYWORD;
+  
+  return map;
+}
+var _tokenMap = createTokenMap();
+
+String classify(Token token) {
+  if (!_tokenMap.containsKey(token.type)) {
+    return Classification.NONE;
+  }
+  var classification = _tokenMap[token.type];
+  
+  // Special case for names that look like types.
+  if (classification == Classification.IDENTIFIER) {
+    final text = token.lexeme;
+    if (_looksLikeType(text)
+        || text == 'num'
+        || text == 'bool'
+        || text == 'int'
+        || text == 'double') {
+      return Classification.TYPE_IDENTIFIER;
+    }
+  }
+  
+  // Color keyword token. Most are colored as keywords.
+  if (classification == Classification.KEYWORD) {
+    if (token.lexeme == 'void') {
+      // Color "void" as a type.
+      return Classification.TYPE_IDENTIFIER;
+    }
+    if (token.lexeme == 'this' || token.lexeme == 'super') {
+      // Color "this" and "super" as identifiers.
+      return Classification.SPECIAL_IDENTIFIER;
+    }
+  }
+  
+  return classification;
+}
+
+bool _looksLikeType(String name) {
+  // If the name looks like an UppercaseName, assume it's a type.
+  return _looksLikePublicType(name) || _looksLikePrivateType(name);
+}
+
+bool _looksLikePublicType(String name) {
+  // If the name looks like an UppercaseName, assume it's a type.
+  return name.length >= 2 && isUpper(name[0]) && isLower(name[1]);
+}
+
+bool _looksLikePrivateType(String name) {
+  // If the name looks like an _UppercaseName, assume it's a type.
+  return (name.length >= 3 && name[0] == '_' && isUpper(name[1])
+    && isLower(name[2]));
+}
+
+// These ensure that they don't return "true" if the string only has symbols.
+bool isUpper(String s) => s.toLowerCase() != s;
+bool isLower(String s) => s.toUpperCase() != s;
diff --git a/pkgs/markdown/lib/src/markdown/block_parser.dart b/pkgs/markdown/lib/src/markdown/block_parser.dart
index e1d04ec..b59c795 100644
--- a/pkgs/markdown/lib/src/markdown/block_parser.dart
+++ b/pkgs/markdown/lib/src/markdown/block_parser.dart
@@ -267,7 +267,6 @@
   Node parse(BlockParser parser) {
     // Get the syntax identifier, if there is one.
     var syntax = pattern.firstMatch(parser.current).group(1);
-    print('syntax: $syntax');
     
     final childLines = parseChildLines(parser);
 
@@ -275,7 +274,7 @@
     childLines.add('');
 
     // Escape the code.
-    final escaped = childLines.join('\n').trim();
+    final escaped = parser.document.classify(syntax, childLines.join('\n').trim());
 
     return new Element.text('pre', escaped);
   }
diff --git a/pkgs/markdown/pubspec.yaml b/pkgs/markdown/pubspec.yaml
index f4436ad..1682a0f 100644
--- a/pkgs/markdown/pubspec.yaml
+++ b/pkgs/markdown/pubspec.yaml
@@ -5,3 +5,4 @@
 homepage: https://github.com/dpeek/dart-markdown
 dependencies:
   unittest: any
+  analyzer_experimental: any