From e2c194f5f70a3de4400e09d0b0abca08062aee77 2014-12-06 20:03:41 From: Min RK 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