From e2c194f5f70a3de4400e09d0b0abca08062aee77 2014-12-06 20:03:41
From: Min RK <benjaminrk@gmail.com>
Date: 2014-12-06 20:03:41
Subject: [PATCH] Merge pull request #6996 from bollwyvl/cm-meta-highlight

Using codemirror mode/meta for mode detection
---

diff --git a/IPython/html/static/base/js/utils.js b/IPython/html/static/base/js/utils.js
index 6d42141..4e60a96 100644
--- a/IPython/html/static/base/js/utils.js
+++ b/IPython/html/static/base/js/utils.js
@@ -5,6 +5,8 @@ define([
     'base/js/namespace',
     'jquery',
     'codemirror/lib/codemirror',
+    // silently upgrades CodeMirror
+    'codemirror/mode/meta',
 ], function(IPython, $, CodeMirror){
     "use strict";
     
@@ -603,20 +605,40 @@ define([
         msg += ajax_error_msg(jqXHR);
         console.log(msg);
     };
-    
+
     var requireCodeMirrorMode = function (mode, callback, errback) {
-        /**
-         * load a mode with requirejs
+        /** 
+         * find a predefined mode or detect from CM metadata then
+         * require and callback with the resolveable mode string: mime or
+         * custom name
          */
-        if (typeof mode != "string") mode = mode.name;
-        if (CodeMirror.modes.hasOwnProperty(mode)) {
-            callback(CodeMirror.modes.mode);
+
+        var modename = (typeof mode == "string") ? mode :
+            mode.mode || mode.name;
+
+        // simplest, cheapest check by mode name: mode may also have config
+        if (CodeMirror.modes.hasOwnProperty(modename)) {
+            // return the full mode object, if it has a name
+            callback(mode.name ? mode : modename);
             return;
         }
+
+        // *somehow* get back a CM.modeInfo-like object that has .mode and
+        // .mime
+        var info = (mode && mode.mode && mode.mime && mode) ||
+            CodeMirror.findModeByName(modename) ||
+            CodeMirror.findModeByExtension(modename.split(".").slice(-1)) ||
+            CodeMirror.findModeByMIME(modename) ||
+            {mode: modename, mime: modename};
+
         require([
                 // might want to use CodeMirror.modeURL here
-                ['codemirror/mode', mode, mode].join('/'),
-            ], callback, errback
+                ['codemirror/mode', info.mode, info.mode].join('/'),
+            ], function() {
+              // return the original mode, as from a kernelspec on first load
+              // or the mimetype, as for most highlighting
+              callback(mode.name ? mode : info.mime);
+            }, errback
         );
     };
     
diff --git a/IPython/html/static/edit/js/editor.js b/IPython/html/static/edit/js/editor.js
index f2db0c8..53320b6 100644
--- a/IPython/html/static/edit/js/editor.js
+++ b/IPython/html/static/edit/js/editor.js
@@ -41,12 +41,10 @@ function($,
                 cm.clearHistory();
 
                 // Find and load the highlighting mode
-                var modeinfo = CodeMirror.findModeByMIME(model.mimetype);
-                if (modeinfo) {
-                    utils.requireCodeMirrorMode(modeinfo.mode, function() {
-                        cm.setOption('mode', modeinfo.mode);
-                    });
-                }
+                utils.requireCodeMirrorMode(model.mimetype, function(spec) {
+                    var mode = CodeMirror.getMode({}, spec);
+                    cm.setOption('mode', mode);
+                });
                 that.save_enabled = true;
             },
             function(error) {
diff --git a/IPython/html/static/notebook/js/cell.js b/IPython/html/static/notebook/js/cell.js
index 9c1daa8..77ca5a5 100644
--- a/IPython/html/static/notebook/js/cell.js
+++ b/IPython/html/static/notebook/js/cell.js
@@ -558,8 +558,8 @@ define([
                         return;
                     }
                     if (mode.search('magic_') !== 0) {
-                        utils.requireCodeMirrorMode(mode, function () {
-                            that.code_mirror.setOption('mode', mode);
+                        utils.requireCodeMirrorMode(mode, function (spec) {
+                            that.code_mirror.setOption('mode', spec);
                         });
                         return;
                     }
@@ -570,7 +570,7 @@ define([
                     if(current_mode == magic_mode){
                         return;
                     }
-                    utils.requireCodeMirrorMode(mode, function () {
+                    utils.requireCodeMirrorMode(mode, function (spec) {
                         // create on the fly a mode that switch between
                         // plain/text and something else, otherwise `%%` is
                         // source of some highlight issues.
@@ -579,7 +579,7 @@ define([
                                 CodeMirror.getMode(config, 'text/plain'),
                                 // always set something on close
                                 {open: open, close: close,
-                                 mode: CodeMirror.getMode(config, mode),
+                                 mode: CodeMirror.getMode(config, spec),
                                  delimStyle: "delimit"
                                 }
                             );
diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js
index 966f71e..3fedb9a 100644
--- a/IPython/html/static/notebook/js/notebook.js
+++ b/IPython/html/static/notebook/js/notebook.js
@@ -102,16 +102,16 @@ define([
                             return code;
                         }
                     }
-                    utils.requireCodeMirrorMode(lang, function () {
+                    utils.requireCodeMirrorMode(lang, function (spec) {
                         var el = document.createElement("div");
-                        var mode = CodeMirror.getMode({}, lang);
+                        var mode = CodeMirror.getMode({}, spec);
                         if (!mode) {
                             console.log("No CodeMirror mode: " + lang);
                             callback(null, code);
                             return;
                         }
                         try {
-                            CodeMirror.runMode(code, mode, el);
+                            CodeMirror.runMode(code, spec, el);
                             callback(null, el.innerHTML);
                         } catch (err) {
                             console.log("Failed to highlight " + lang + " code", err);
@@ -1585,17 +1585,16 @@ define([
         }
         this.codemirror_mode = newmode;
         codecell.CodeCell.options_default.cm_config.mode = newmode;
-        var modename = newmode.mode || newmode.name || newmode;
         
         var that = this;
-        utils.requireCodeMirrorMode(modename, function () {
+        utils.requireCodeMirrorMode(newmode, function (spec) {
             that.get_cells().map(function(cell, i) {
                 if (cell.cell_type === 'code'){
-                    cell.code_mirror.setOption('mode', newmode);
+                    cell.code_mirror.setOption('mode', spec);
                     // This is currently redundant, because cm_config ends up as
                     // codemirror's own .options object, but I don't want to
                     // rely on that.
-                    cell.cm_config.mode = newmode;
+                    cell.cm_config.mode = spec;
                 }
             });
         });
diff --git a/IPython/html/static/notebook/less/highlight-refs.less b/IPython/html/static/notebook/less/highlight-refs.less
new file mode 100644
index 0000000..a2c0ab6
--- /dev/null
+++ b/IPython/html/static/notebook/less/highlight-refs.less
@@ -0,0 +1,5 @@
+/* load the codemirror defaults as LESS so that highlight.less
+   can load default theme declarations by reference without pulling in the 
+   nasty positioning
+*/
+@import (less) "../../components/codemirror/lib/codemirror.css";
diff --git a/IPython/html/static/notebook/less/highlight.less b/IPython/html/static/notebook/less/highlight.less
index 15a878c..d0b2bf2 100644
--- a/IPython/html/static/notebook/less/highlight.less
+++ b/IPython/html/static/notebook/less/highlight.less
@@ -5,160 +5,108 @@ Adapted from GitHub theme
 
 */
 
-pre code {
-  display: block;
-  padding: 0.5em;
+@import (reference) "highlight-refs.less";
+
+@highlight-base: #000;
+
+.highlight-base{
+  color: @highlight-base;
+}
+
+.highlight-variable{
+  .highlight-base();
+}
+
+.highlight-variable-2{
+  color: lighten(@highlight-base, 10%);
 }
 
-.highlight-base,
-pre code,
-pre .subst,
-pre .tag .title,
-pre .lisp .title,
-pre .clojure .built_in,
-pre .nginx .title {
-  color: black;
+.highlight-variable-3{
+  color: lighten(@highlight-base, 20%);
 }
 
-.highlight-string,
-pre .string,
-pre .constant,
-pre .parent,
-pre .tag .value,
-pre .rules .value,
-pre .rules .value .number,
-pre .preprocessor,
-pre .ruby .symbol,
-pre .ruby .symbol .string,
-pre .aggregate,
-pre .template_tag,
-pre .django .variable,
-pre .smalltalk .class,
-pre .addition,
-pre .flow,
-pre .stream,
-pre .bash .variable,
-pre .apache .tag,
-pre .apache .cbracket,
-pre .tex .command,
-pre .tex .special,
-pre .erlang_repl .function_or_atom,
-pre .markdown .header {
+.highlight-string{
   color: #BA2121;
 }
 
-.highlight-comment,
-pre .comment,
-pre .annotation,
-pre .template_comment,
-pre .diff .header,
-pre .chunk,
-pre .markdown .blockquote {
+.highlight-comment{
   color: #408080;
   font-style: italic;
 }
 
-.highlight-number,
-pre .number,
-pre .date,
-pre .regexp,
-pre .literal,
-pre .smalltalk .symbol,
-pre .smalltalk .char,
-pre .go .constant,
-pre .change,
-pre .markdown .bullet,
-pre .markdown .link_url {
+.highlight-number{
   color: #080;
 }
 
-pre .label,
-pre .javadoc,
-pre .ruby .string,
-pre .decorator,
-pre .filter .argument,
-pre .localvars,
-pre .array,
-pre .attr_selector,
-pre .important,
-pre .pseudo,
-pre .pi,
-pre .doctype,
-pre .deletion,
-pre .envvar,
-pre .shebang,
-pre .apache .sqbracket,
-pre .nginx .built_in,
-pre .tex .formula,
-pre .erlang_repl .reserved,
-pre .prompt,
-pre .markdown .link_label,
-pre .vhdl .attribute,
-pre .clojure .attribute,
-pre .coffeescript .property {
-  color: #88F
+.highlight-atom{
+  color: #88F;
 }
 
-.highlight-keyword,
-pre .keyword,
-pre .id,
-pre .phpdoc,
-pre .aggregate,
-pre .css .tag,
-pre .javadoctag,
-pre .phpdoc,
-pre .yardoctag,
-pre .smalltalk .class,
-pre .winutils,
-pre .bash .variable,
-pre .apache .tag,
-pre .go .typename,
-pre .tex .command,
-pre .markdown .strong,
-pre .request,
-pre .status {
+.highlight-keyword{
   color: #008000;
   font-weight: bold;
 }
 
-.highlight-builtin,
-pre .built_in {
+.highlight-builtin{
   color: #008000;
 }
 
-pre .markdown .emphasis {
-  font-style: italic;
+.highlight-error{
+  color: #f00;
 }
 
-pre .nginx .built_in {
-  font-weight: normal;
+.highlight-operator{
+  color: #AA22FF;
+  font-weight: bold;
 }
 
-pre .coffeescript .javascript,
-pre .javascript .xml,
-pre .tex .formula,
-pre .xml .javascript,
-pre .xml .vbscript,
-pre .xml .css,
-pre .xml .cdata {
-  opacity: 0.5;
+.highlight-meta{
+  color: #AA22FF;
 }
 
+/* previously not defined, copying from default codemirror */
+.highlight-def{ .cm-s-default.cm-def() }
+.highlight-punctuation{ .cm-s-default.cm-punctuation() }
+.highlight-property{ .cm-s-default.cm-property() }
+.highlight-string-2{ .cm-s-default.cm-string-2() }
+.highlight-qualifier{ .cm-s-default.cm-qualifier() }
+.highlight-bracket{ .cm-s-default.cm-bracket() }
+.highlight-tag{ .cm-s-default.cm-tag() }
+.highlight-attribute{ .cm-s-default.cm-attribute() }
+.highlight-header{ .cm-s-default.cm-header() }
+.highlight-quote{ .cm-s-default.cm-quote() }
+.highlight-link{ .cm-s-default.cm-link() }
+
+
 /* apply the same style to codemirror */
-.cm-s-ipython {
-     span.cm-variable { .highlight-base()}
-     span.cm-keyword { .highlight-keyword() }
-     span.cm-number { .highlight-number() }
-     span.cm-comment { .highlight-comment() }
-     span.cm-string { .highlight-string()}
-     span.cm-builtin { .highlight-builtin() }
-     span.cm-error { color: #f00; }
-     span.cm-operator {color: #AA22FF; font-weight: bold;}
-     span.cm-meta {color: #AA22FF;}
-
-     span.cm-tab {
-             background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
-             background-position: right;
-             background-repeat: no-repeat;
-    }
+.cm-s-ipython span {
+  &.cm-keyword      { .highlight-keyword() }
+  &.cm-atom         { .highlight-atom() }
+  &.cm-number       { .highlight-number() }
+  &.cm-def          { .highlight-def() }
+  &.cm-variable     { .highlight-variable() }
+  &.cm-punctuation  { .highlight-punctuation() }
+  &.cm-property     { .highlight-property() }
+  &.cm-operator     { .highlight-operator() }
+  &.cm-variable-2   { .highlight-variable-2() }
+  &.cm-variable-3   { .highlight-variable-3() }
+  &.cm-comment      { .highlight-comment() }
+  &.cm-string       { .highlight-string() }
+  &.cm-string-2     { .highlight-string-2() }
+  &.cm-meta         { .highlight-meta() }
+  &.cm-qualifier    { .highlight-qualifier() }
+  &.cm-builtin      { .highlight-builtin() }
+  &.cm-bracket      { .highlight-bracket() }
+  &.cm-tag          { .highlight-tag() }
+  &.cm-attribute    { .highlight-attribute() }
+  &.cm-header       { .highlight-header() }
+  &.cm-quote        { .highlight-quote() }
+  &.cm-link         { .highlight-link() }
+  &.cm-error        { .highlight-error() }
+
+  &.cm-tab {
+    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
+    background-position: right;
+    background-repeat: no-repeat;
+  }
 }
diff --git a/IPython/html/static/style/ipython.min.css b/IPython/html/static/style/ipython.min.css
index 913feb0..84654de 100644
--- a/IPython/html/static/style/ipython.min.css
+++ b/IPython/html/static/style/ipython.min.css
@@ -563,145 +563,103 @@ Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiac
 Adapted from GitHub theme
 
 */
-pre code {
-  display: block;
-  padding: 0.5em;
-}
-.highlight-base,
-pre code,
-pre .subst,
-pre .tag .title,
-pre .lisp .title,
-pre .clojure .built_in,
-pre .nginx .title {
-  color: black;
+.highlight-base {
+  color: #000000;
+}
+.highlight-variable {
+  color: #000000;
+}
+.highlight-variable-2 {
+  color: #1a1a1a;
+}
+.highlight-variable-3 {
+  color: #333333;
 }
-.highlight-string,
-pre .string,
-pre .constant,
-pre .parent,
-pre .tag .value,
-pre .rules .value,
-pre .rules .value .number,
-pre .preprocessor,
-pre .ruby .symbol,
-pre .ruby .symbol .string,
-pre .aggregate,
-pre .template_tag,
-pre .django .variable,
-pre .smalltalk .class,
-pre .addition,
-pre .flow,
-pre .stream,
-pre .bash .variable,
-pre .apache .tag,
-pre .apache .cbracket,
-pre .tex .command,
-pre .tex .special,
-pre .erlang_repl .function_or_atom,
-pre .markdown .header {
+.highlight-string {
   color: #BA2121;
 }
-.highlight-comment,
-pre .comment,
-pre .annotation,
-pre .template_comment,
-pre .diff .header,
-pre .chunk,
-pre .markdown .blockquote {
+.highlight-comment {
   color: #408080;
   font-style: italic;
 }
-.highlight-number,
-pre .number,
-pre .date,
-pre .regexp,
-pre .literal,
-pre .smalltalk .symbol,
-pre .smalltalk .char,
-pre .go .constant,
-pre .change,
-pre .markdown .bullet,
-pre .markdown .link_url {
+.highlight-number {
   color: #080;
 }
-pre .label,
-pre .javadoc,
-pre .ruby .string,
-pre .decorator,
-pre .filter .argument,
-pre .localvars,
-pre .array,
-pre .attr_selector,
-pre .important,
-pre .pseudo,
-pre .pi,
-pre .doctype,
-pre .deletion,
-pre .envvar,
-pre .shebang,
-pre .apache .sqbracket,
-pre .nginx .built_in,
-pre .tex .formula,
-pre .erlang_repl .reserved,
-pre .prompt,
-pre .markdown .link_label,
-pre .vhdl .attribute,
-pre .clojure .attribute,
-pre .coffeescript .property {
-  color: #8888ff;
-}
-.highlight-keyword,
-pre .keyword,
-pre .id,
-pre .phpdoc,
-pre .aggregate,
-pre .css .tag,
-pre .javadoctag,
-pre .phpdoc,
-pre .yardoctag,
-pre .smalltalk .class,
-pre .winutils,
-pre .bash .variable,
-pre .apache .tag,
-pre .go .typename,
-pre .tex .command,
-pre .markdown .strong,
-pre .request,
-pre .status {
+.highlight-atom {
+  color: #88F;
+}
+.highlight-keyword {
   color: #008000;
   font-weight: bold;
 }
-.highlight-builtin,
-pre .built_in {
+.highlight-builtin {
   color: #008000;
 }
-pre .markdown .emphasis {
-  font-style: italic;
+.highlight-error {
+  color: #f00;
 }
-pre .nginx .built_in {
-  font-weight: normal;
+.highlight-operator {
+  color: #AA22FF;
+  font-weight: bold;
+}
+.highlight-meta {
+  color: #AA22FF;
 }
-pre .coffeescript .javascript,
-pre .javascript .xml,
-pre .tex .formula,
-pre .xml .javascript,
-pre .xml .vbscript,
-pre .xml .css,
-pre .xml .cdata {
-  opacity: 0.5;
+/* previously not defined, copying from default codemirror */
+.highlight-def {
+  color: #00f;
 }
-/* apply the same style to codemirror */
-.cm-s-ipython span.cm-variable {
-  color: black;
+.highlight-string-2 {
+  color: #f50;
+}
+.highlight-qualifier {
+  color: #555;
+}
+.highlight-bracket {
+  color: #997;
+}
+.highlight-tag {
+  color: #170;
 }
+.highlight-attribute {
+  color: #00c;
+}
+.highlight-header {
+  color: blue;
+}
+.highlight-quote {
+  color: #090;
+}
+.highlight-link {
+  color: #00c;
+}
+/* apply the same style to codemirror */
 .cm-s-ipython span.cm-keyword {
   color: #008000;
   font-weight: bold;
 }
+.cm-s-ipython span.cm-atom {
+  color: #88F;
+}
 .cm-s-ipython span.cm-number {
   color: #080;
 }
+.cm-s-ipython span.cm-def {
+  color: #00f;
+}
+.cm-s-ipython span.cm-variable {
+  color: #000000;
+}
+.cm-s-ipython span.cm-operator {
+  color: #AA22FF;
+  font-weight: bold;
+}
+.cm-s-ipython span.cm-variable-2 {
+  color: #1a1a1a;
+}
+.cm-s-ipython span.cm-variable-3 {
+  color: #333333;
+}
 .cm-s-ipython span.cm-comment {
   color: #408080;
   font-style: italic;
@@ -709,18 +667,38 @@ pre .xml .cdata {
 .cm-s-ipython span.cm-string {
   color: #BA2121;
 }
+.cm-s-ipython span.cm-string-2 {
+  color: #f50;
+}
+.cm-s-ipython span.cm-meta {
+  color: #AA22FF;
+}
+.cm-s-ipython span.cm-qualifier {
+  color: #555;
+}
 .cm-s-ipython span.cm-builtin {
   color: #008000;
 }
-.cm-s-ipython span.cm-error {
-  color: #f00;
+.cm-s-ipython span.cm-bracket {
+  color: #997;
 }
-.cm-s-ipython span.cm-operator {
-  color: #AA22FF;
-  font-weight: bold;
+.cm-s-ipython span.cm-tag {
+  color: #170;
 }
-.cm-s-ipython span.cm-meta {
-  color: #AA22FF;
+.cm-s-ipython span.cm-attribute {
+  color: #00c;
+}
+.cm-s-ipython span.cm-header {
+  color: blue;
+}
+.cm-s-ipython span.cm-quote {
+  color: #090;
+}
+.cm-s-ipython span.cm-link {
+  color: #00c;
+}
+.cm-s-ipython span.cm-error {
+  color: #f00;
 }
 .cm-s-ipython span.cm-tab {
   background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
diff --git a/IPython/html/static/style/style.min.css b/IPython/html/static/style/style.min.css
index 15ee5ca..20ce81a 100644
--- a/IPython/html/static/style/style.min.css
+++ b/IPython/html/static/style/style.min.css
@@ -8469,145 +8469,103 @@ Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiac
 Adapted from GitHub theme
 
 */
-pre code {
-  display: block;
-  padding: 0.5em;
-}
-.highlight-base,
-pre code,
-pre .subst,
-pre .tag .title,
-pre .lisp .title,
-pre .clojure .built_in,
-pre .nginx .title {
-  color: black;
+.highlight-base {
+  color: #000000;
+}
+.highlight-variable {
+  color: #000000;
+}
+.highlight-variable-2 {
+  color: #1a1a1a;
+}
+.highlight-variable-3 {
+  color: #333333;
 }
-.highlight-string,
-pre .string,
-pre .constant,
-pre .parent,
-pre .tag .value,
-pre .rules .value,
-pre .rules .value .number,
-pre .preprocessor,
-pre .ruby .symbol,
-pre .ruby .symbol .string,
-pre .aggregate,
-pre .template_tag,
-pre .django .variable,
-pre .smalltalk .class,
-pre .addition,
-pre .flow,
-pre .stream,
-pre .bash .variable,
-pre .apache .tag,
-pre .apache .cbracket,
-pre .tex .command,
-pre .tex .special,
-pre .erlang_repl .function_or_atom,
-pre .markdown .header {
+.highlight-string {
   color: #BA2121;
 }
-.highlight-comment,
-pre .comment,
-pre .annotation,
-pre .template_comment,
-pre .diff .header,
-pre .chunk,
-pre .markdown .blockquote {
+.highlight-comment {
   color: #408080;
   font-style: italic;
 }
-.highlight-number,
-pre .number,
-pre .date,
-pre .regexp,
-pre .literal,
-pre .smalltalk .symbol,
-pre .smalltalk .char,
-pre .go .constant,
-pre .change,
-pre .markdown .bullet,
-pre .markdown .link_url {
+.highlight-number {
   color: #080;
 }
-pre .label,
-pre .javadoc,
-pre .ruby .string,
-pre .decorator,
-pre .filter .argument,
-pre .localvars,
-pre .array,
-pre .attr_selector,
-pre .important,
-pre .pseudo,
-pre .pi,
-pre .doctype,
-pre .deletion,
-pre .envvar,
-pre .shebang,
-pre .apache .sqbracket,
-pre .nginx .built_in,
-pre .tex .formula,
-pre .erlang_repl .reserved,
-pre .prompt,
-pre .markdown .link_label,
-pre .vhdl .attribute,
-pre .clojure .attribute,
-pre .coffeescript .property {
-  color: #8888ff;
-}
-.highlight-keyword,
-pre .keyword,
-pre .id,
-pre .phpdoc,
-pre .aggregate,
-pre .css .tag,
-pre .javadoctag,
-pre .phpdoc,
-pre .yardoctag,
-pre .smalltalk .class,
-pre .winutils,
-pre .bash .variable,
-pre .apache .tag,
-pre .go .typename,
-pre .tex .command,
-pre .markdown .strong,
-pre .request,
-pre .status {
+.highlight-atom {
+  color: #88F;
+}
+.highlight-keyword {
   color: #008000;
   font-weight: bold;
 }
-.highlight-builtin,
-pre .built_in {
+.highlight-builtin {
   color: #008000;
 }
-pre .markdown .emphasis {
-  font-style: italic;
+.highlight-error {
+  color: #f00;
 }
-pre .nginx .built_in {
-  font-weight: normal;
+.highlight-operator {
+  color: #AA22FF;
+  font-weight: bold;
 }
-pre .coffeescript .javascript,
-pre .javascript .xml,
-pre .tex .formula,
-pre .xml .javascript,
-pre .xml .vbscript,
-pre .xml .css,
-pre .xml .cdata {
-  opacity: 0.5;
+.highlight-meta {
+  color: #AA22FF;
 }
-/* apply the same style to codemirror */
-.cm-s-ipython span.cm-variable {
-  color: black;
+/* previously not defined, copying from default codemirror */
+.highlight-def {
+  color: #00f;
+}
+.highlight-string-2 {
+  color: #f50;
+}
+.highlight-qualifier {
+  color: #555;
+}
+.highlight-bracket {
+  color: #997;
+}
+.highlight-tag {
+  color: #170;
 }
+.highlight-attribute {
+  color: #00c;
+}
+.highlight-header {
+  color: blue;
+}
+.highlight-quote {
+  color: #090;
+}
+.highlight-link {
+  color: #00c;
+}
+/* apply the same style to codemirror */
 .cm-s-ipython span.cm-keyword {
   color: #008000;
   font-weight: bold;
 }
+.cm-s-ipython span.cm-atom {
+  color: #88F;
+}
 .cm-s-ipython span.cm-number {
   color: #080;
 }
+.cm-s-ipython span.cm-def {
+  color: #00f;
+}
+.cm-s-ipython span.cm-variable {
+  color: #000000;
+}
+.cm-s-ipython span.cm-operator {
+  color: #AA22FF;
+  font-weight: bold;
+}
+.cm-s-ipython span.cm-variable-2 {
+  color: #1a1a1a;
+}
+.cm-s-ipython span.cm-variable-3 {
+  color: #333333;
+}
 .cm-s-ipython span.cm-comment {
   color: #408080;
   font-style: italic;
@@ -8615,18 +8573,38 @@ pre .xml .cdata {
 .cm-s-ipython span.cm-string {
   color: #BA2121;
 }
+.cm-s-ipython span.cm-string-2 {
+  color: #f50;
+}
+.cm-s-ipython span.cm-meta {
+  color: #AA22FF;
+}
+.cm-s-ipython span.cm-qualifier {
+  color: #555;
+}
 .cm-s-ipython span.cm-builtin {
   color: #008000;
 }
-.cm-s-ipython span.cm-error {
-  color: #f00;
+.cm-s-ipython span.cm-bracket {
+  color: #997;
 }
-.cm-s-ipython span.cm-operator {
-  color: #AA22FF;
-  font-weight: bold;
+.cm-s-ipython span.cm-tag {
+  color: #170;
 }
-.cm-s-ipython span.cm-meta {
-  color: #AA22FF;
+.cm-s-ipython span.cm-attribute {
+  color: #00c;
+}
+.cm-s-ipython span.cm-header {
+  color: blue;
+}
+.cm-s-ipython span.cm-quote {
+  color: #090;
+}
+.cm-s-ipython span.cm-link {
+  color: #00c;
+}
+.cm-s-ipython span.cm-error {
+  color: #f00;
 }
 .cm-s-ipython span.cm-tab {
   background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
diff --git a/IPython/html/tests/base/highlight.js b/IPython/html/tests/base/highlight.js
new file mode 100644
index 0000000..dbab79e
--- /dev/null
+++ b/IPython/html/tests/base/highlight.js
@@ -0,0 +1,58 @@
+casper.notebook_test(function () {
+    this.on('remote.callback', function(data){
+        if(data.error_expected){
+            that.test.assertEquals(
+                data.error,
+                data.expected,
+                "!highlight: " + data.provided + " errors " + data.expected
+            );
+        }else{
+            that.test.assertEquals(
+                data.observed,
+                data.expected,
+                "highlight: " + data.provided + " as " + data.expected
+            );
+        }
+    });
+    
+    var that = this;
+    // syntax highlighting
+    [
+        {to: "gfm"},
+        {to: "python"},
+        {to: "ipython"},
+        {to: "ipythongfm"},
+        {to: "text/x-markdown", from: [".md"]},
+        {to: "text/x-python", from: [".py", "Python"]},
+        {to: "application/json", from: ["json", "JSON"]},
+        {to: "text/x-ruby", from: [".rb", "ruby", "Ruby"]},
+        {to: "application/ld+json", from: ["json-ld", "JSON-LD"]},
+        {from: [".pyc"], error: true},
+        {from: ["../"], error: true},
+        {from: ["//"], error: true},
+    ].map(function (mode) {
+        (mode.from || []).concat(mode.to || []).map(function(from){
+            casper.evaluate(function(from, expected, error_expected){
+                IPython.utils.requireCodeMirrorMode(from, function(observed){
+                    window.callPhantom({
+                        provided: from,
+                        expected: expected,
+                        observed: observed,
+                        error_expected: error_expected
+                    });
+                }, function(error){
+                    window.callPhantom({
+                        provided: from,
+                        expected: expected,
+                        error: error,
+                        error_expected: error_expected
+                    }); 
+                });
+            }, {
+                from: from,
+                expected: mode.to,
+                error_expected: mode.error
+            });
+        });
+    });
+});
\ No newline at end of file