Skip to content
This repository

Update codemirror to 2.15 and make the code internally more version-agnostic #850

Merged
merged 5 commits into from over 2 years ago

2 participants

Fernando Perez Brian E. Granger
Fernando Perez
Owner

Just updated to the recently released CM and changed things around a little so that we don't have an explicit version number path inside our templates.

Since 0.12 may live for a while in a long-term Ubuntu release (12.04), it would be nice to release with the most updated CM...

added some commits October 09, 2011
Fernando Perez Update CodeMirror code to v2.15 6652b19
Fernando Perez Do not use version # in codemirror directory name.
Simply call it 'codemirror', so we don't have explicit version numbers
inside a bunch of files.

A file called ipython-version-N.NN will be kept to easily let us know
which version we're shipping with IPython.
265d40c
Fernando Perez Update templates to new directory name for codemirror. 5b206ff
Brian E. Granger
Owner
Fernando Perez
Owner

No, I hadn't realized that you had made changes. If they were made in a single commit, then it should be relatively easy to reapply them as a patch, do you have the commit number?

And what I can do is apply them again as a single commit and record that info in a little README, so that it's easy later to apply again when we upgrade CM. Eventually the right way to do this is to keep the patch set separately using something like stgit, but for small changes we can get away with a one-off manual process.

Brian E. Granger
Owner
Fernando Perez
Owner
Brian E. Granger
Owner
Fernando Perez
Owner

Found it, the only difference from CM 2.12 and your code is this:

diff --git a/IPython/frontend/html/notebook/static/codemirror-2.12/mode/python/python.js b/IPython/frontend/html/notebook/static/codemirror-2.12/mode/python/python.js
index baeec03..0cda2aa 100644
--- a/IPython/frontend/html/notebook/static/codemirror-2.12/mode/python/python.js
+++ b/IPython/frontend/html/notebook/static/codemirror-2.12/mode/python/python.js
@@ -5,7 +5,7 @@ CodeMirror.defineMode("python", function(conf) {
         return new RegExp("^((" + words.join(")|(") + "))\\b");
     }
     
-    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~!]");
+    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~!\\?]");
     var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
     var doubleOperators = new RegExp("^((==)|(!=)|(=)|()|(>)|(//)|(\\*\\*))");
     var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))")

It's a single line change where you added some operators. I'm now going to see how much of that is actually even needed in 2.15, since they've also updated the python code somewhat.

So this is going to be pretty easy, in fact.

Fernando Perez
Owner

OK, @ellisonbg, I've applied back the changes you had, and it was done as a single-commit in bef6551 so we can find them again easily later on. If this ever gets big we can make a little patch queue for it, but something this small is just as easily copy/pasted by hand, esp. now that it's in its own commit and hence easy to find.

I'll make a little file with this info so we know what to do in future updates too.

Fernando Perez
Owner

OK, ipython-specific readme added, let me know if you see anything else that sticks out prior to merge.

Thanks for the feedback!

Brian E. Granger
Owner
Fernando Perez
Owner

@ellisonbg, does this look OK to merge, or do you want anything else on it? Just being a good citizen here and not merging my own stuff without someone else giving the final OK :)

Brian E. Granger
Owner
Fernando Perez fperez merged commit e5a1dff into from October 14, 2011
Fernando Perez fperez closed this October 14, 2011
Fernando Perez fperez referenced this pull request from a commit January 10, 2012
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 5 unique commits by 1 author.

Oct 09, 2011
Fernando Perez Update CodeMirror code to v2.15 6652b19
Fernando Perez Do not use version # in codemirror directory name.
Simply call it 'codemirror', so we don't have explicit version numbers
inside a bunch of files.

A file called ipython-version-N.NN will be kept to easily let us know
which version we're shipping with IPython.
265d40c
Fernando Perez Update templates to new directory name for codemirror. 5b206ff
Oct 13, 2011
Fernando Perez IPython-specific changes to CodeMirror: recognize '?' in Python mode. bef6551
Fernando Perez Add a README with version and ipython-specific changes info. c0fb925
This page is out of date. Refresh to see the latest.

Showing 30 changed files with 810 additions and 135 deletions. Show diff stats Hide diff stats

  1. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/LICENSE
  2. 33  IPython/frontend/html/notebook/static/codemirror/README-IPython.rst
  3. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/README.md
  4. 1  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/lib/codemirror.css
  5. 211  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/lib/codemirror.js
  6. 2  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/lib/overlay.js
  7. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/lib/runmode.js
  8. 6  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/css/css.js
  9. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/css/index.html
  10. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/htmlmixed/htmlmixed.js
  11. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/htmlmixed/index.html
  12. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/javascript/index.html
  13. 8  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/javascript/javascript.js
  14. 340  IPython/frontend/html/notebook/static/codemirror/mode/markdown/index.html
  15. 10  IPython/frontend/html/notebook/static/codemirror/mode/markdown/markdown.css
  16. 230  IPython/frontend/html/notebook/static/codemirror/mode/markdown/markdown.js
  17. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/python/LICENSE.txt
  18. 2  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/python/index.html
  19. 67  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/python/python.js
  20. 1  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/rst/index.html
  21. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/rst/rst.css
  22. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/rst/rst.js
  23. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/xml/index.html
  24. 8  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/mode/xml/xml.js
  25. 1  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/theme/default.css
  26. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/theme/elegant.css
  27. 1  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/theme/ipython.css
  28. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/theme/neat.css
  29. 0  IPython/frontend/html/notebook/static/{codemirror-2.12 → codemirror}/theme/night.css
  30. 24  IPython/frontend/html/notebook/templates/notebook.html
0  ...tend/html/notebook/static/codemirror-2.12/LICENSE → .../frontend/html/notebook/static/codemirror/LICENSE
File renamed without changes
33  IPython/frontend/html/notebook/static/codemirror/README-IPython.rst
Source Rendered
... ...
@@ -0,0 +1,33 @@
  1
+=======================
  2
+ CodeMirror in IPython
  3
+=======================
  4
+
  5
+We carry a mostly unmodified copy of CodeMirror.  The current version we use
  6
+is (*please update this information when updating versions*)::
  7
+
  8
+  CodeMirror 2.15
  9
+
  10
+The only changes we've applied so far are these::
  11
+
  12
+    diff --git a/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js b/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js
  13
+    index ca94e7a..fc9a503 100644
  14
+    --- a/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js
  15
+    +++ b/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js
  16
+    @@ -5,7 +5,11 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
  17
+	     return new RegExp("^((" + words.join(")|(") + "))\\b");
  18
+	 }
  19
+
  20
+    -    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
  21
+    +    // IPython-specific changes: add '?' as recognized character.
  22
+    +    //var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
  23
+    +    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
  24
+    +    // End IPython changes.
  25
+    +    
  26
+	 var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
  27
+	 var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
  28
+	 var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
  29
+
  30
+
  31
+In practice it's just a one-line change, adding `\\?` to singleOperators,
  32
+surrounded by a comment.  We'll turn this into a proper patchset if it ever
  33
+gets more complicated than this, but for now this note should be enough.
0  ...nd/html/notebook/static/codemirror-2.12/README.md → ...rontend/html/notebook/static/codemirror/README.md
Source Rendered
File renamed without changes
1  ...otebook/static/codemirror-2.12/lib/codemirror.css → ...tml/notebook/static/codemirror/lib/codemirror.css
@@ -13,6 +13,7 @@
13 13
 
14 14
 .CodeMirror-gutter {
15 15
   position: absolute; left: 0; top: 0;
  16
+  z-index: 10;
16 17
   background-color: #f7f7f7;
17 18
   border-right: 1px solid #eee;
18 19
   min-width: 2em;
211  ...notebook/static/codemirror-2.12/lib/codemirror.js → ...html/notebook/static/codemirror/lib/codemirror.js
@@ -20,14 +20,15 @@ var CodeMirror = (function() {
20 20
     // This mess creates the base DOM structure for the editor.
21 21
     wrapper.innerHTML =
22 22
       '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
23  
-        '<textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div>' +
  23
+        '<textarea style="position: absolute; width: 2px;" wrap="off" ' +
  24
+          'autocorrect="off" autocapitalize="off"></textarea></div>' +
24 25
       '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
25 26
         '<div style="position: relative">' + // Set to the height of the text, causes scrolling
26 27
           '<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
27 28
           '<div style="position: relative">' + // Moved around its parent to cover visible view
28 29
             '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
29 30
             // Provides positioning relative to (visible) text origin
30  
-            '<div class="CodeMirror-lines"><div style="position: relative">' +
  31
+            '<div class="CodeMirror-lines"><div style="position: relative" draggable="true">' +
31 32
               '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
32 33
               '<div></div>' + // This DIV contains the actual code
33 34
             '</div></div></div></div></div>';
@@ -59,10 +60,10 @@ var CodeMirror = (function() {
59 60
     // whether the user is holding shift. reducedSelection is a hack
60 61
     // to get around the fact that we can't create inverted
61 62
     // selections. See below.
62  
-    var shiftSelecting, reducedSelection, lastDoubleClick;
  63
+    var shiftSelecting, reducedSelection, lastClick, lastDoubleClick;
63 64
     // Variables used by startOperation/endOperation to track what
64 65
     // happened during the operation.
65  
-    var updateInput, changes, textChanged, selectionChanged, leaveInputAlone;
  66
+    var updateInput, changes, textChanged, selectionChanged, leaveInputAlone, gutterDirty;
66 67
     // Current visible range (may be bigger than the view window).
67 68
     var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
68 69
     // editing will hold an object describing the things we put in the
@@ -79,12 +80,16 @@ var CodeMirror = (function() {
79 80
 
80 81
     // Register our event handlers.
81 82
     connect(scroller, "mousedown", operation(onMouseDown));
  83
+    connect(lineSpace, "dragstart", onDragStart);
82 84
     // Gecko browsers fire contextmenu *after* opening the menu, at
83 85
     // which point we can't mess with it anymore. Context menu is
84 86
     // handled in onMouseDown for Gecko.
85 87
     if (!gecko) connect(scroller, "contextmenu", onContextMenu);
86  
-    connect(code, "dblclick", operation(onDblClick));
87  
-    connect(scroller, "scroll", function() {updateDisplay([]); if (options.onScroll) options.onScroll(instance);});
  88
+    connect(scroller, "scroll", function() {
  89
+      updateDisplay([]);
  90
+      if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
  91
+      if (options.onScroll) options.onScroll(instance);
  92
+    });
88 93
     connect(window, "resize", function() {updateDisplay(true);});
89 94
     connect(input, "keyup", operation(onKeyUp));
90 95
     connect(input, "keydown", operation(onKeyDown));
@@ -98,8 +103,8 @@ var CodeMirror = (function() {
98 103
     connect(scroller, "paste", function(){focusInput(); fastPoll();});
99 104
     connect(input, "paste", function(){fastPoll();});
100 105
     connect(input, "cut", function(){fastPoll();});
101  
-    
102  
-    // IE throws unspecified error in certain cases, when 
  106
+
  107
+    // IE throws unspecified error in certain cases, when
103 108
     // trying to access activeElement before onload
104 109
     var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
105 110
     if (hasFocus) setTimeout(onFocus, 20);
@@ -111,7 +116,7 @@ var CodeMirror = (function() {
111 116
     // range checking and/or clipping. operation is used to wrap the
112 117
     // call so that changes it makes are tracked, and the display is
113 118
     // updated afterwards.
114  
-    var instance = {
  119
+    var instance = wrapper.CodeMirror = {
115 120
       getValue: getValue,
116 121
       setValue: operation(setValue),
117 122
       getSelection: getSelection,
@@ -119,7 +124,8 @@ var CodeMirror = (function() {
119 124
       focus: function(){focusInput(); onFocus(); fastPoll();},
120 125
       setOption: function(option, value) {
121 126
         options[option] = value;
122  
-        if (option == "lineNumbers" || option == "gutter") gutterChanged();
  127
+        if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber")
  128
+          operation(gutterChanged)();
123 129
         else if (option == "mode" || option == "indentUnit") loadMode();
124 130
         else if (option == "readOnly" && value == "nocursor") input.blur();
125 131
         else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
@@ -127,7 +133,9 @@ var CodeMirror = (function() {
127 133
       getOption: function(option) {return options[option];},
128 134
       undo: operation(undo),
129 135
       redo: operation(redo),
130  
-      indentLine: operation(function(n) {if (isLine(n)) indentLine(n, "smart");}),
  136
+      indentLine: operation(function(n, dir) {
  137
+        if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
  138
+      }),
131 139
       historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
132 140
       matchBrackets: operation(function(){matchBrackets(true);}),
133 141
       getTokenAt: function(pos) {
@@ -150,18 +158,17 @@ var CodeMirror = (function() {
150 158
       },
151 159
       getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
152 160
       markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
153  
-      setMarker: addGutterMarker,
154  
-      clearMarker: removeGutterMarker,
  161
+      setMarker: operation(addGutterMarker),
  162
+      clearMarker: operation(removeGutterMarker),
155 163
       setLineClass: operation(setLineClass),
156 164
       lineInfo: lineInfo,
157  
-      addWidget: function(pos, node, scroll, where) {
  165
+      addWidget: function(pos, node, scroll, vert, horiz) {
158 166
         pos = localCoords(clipPos(pos));
159 167
         var top = pos.yBot, left = pos.x;
160 168
         node.style.position = "absolute";
161 169
         code.appendChild(node);
162  
-        node.style.left = left + "px";
163  
-        if (where == "over") top = pos.y;
164  
-        else if (where == "near") {
  170
+        if (vert == "over") top = pos.y;
  171
+        else if (vert == "near") {
165 172
           var vspace = Math.max(scroller.offsetHeight, lines.length * lineHeight()),
166 173
               hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
167 174
           if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
@@ -170,7 +177,15 @@ var CodeMirror = (function() {
170 177
             left = hspace - node.offsetWidth;
171 178
         }
172 179
         node.style.top = (top + paddingTop()) + "px";
173  
-        node.style.left = (left + paddingLeft()) + "px";
  180
+        node.style.left = node.style.right = "";
  181
+        if (horiz == "right") {
  182
+          left = code.clientWidth - node.offsetWidth;
  183
+          node.style.right = "0px";
  184
+        } else {
  185
+          if (horiz == "left") left = 0;
  186
+          else if (horiz == "middle") left = (code.clientWidth - node.offsetWidth) / 2;
  187
+          node.style.left = (left + paddingLeft()) + "px";
  188
+        }
174 189
         if (scroll)
175 190
           scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
176 191
       },
@@ -200,7 +215,8 @@ var CodeMirror = (function() {
200 215
       refresh: function(){updateDisplay(true);},
201 216
       getInputField: function(){return input;},
202 217
       getWrapperElement: function(){return wrapper;},
203  
-      getScrollerElement: function(){return scroller;}
  218
+      getScrollerElement: function(){return scroller;},
  219
+      getGutterElement: function(){return gutter;}
204 220
     };
205 221
 
206 222
     function setValue(code) {
@@ -209,6 +225,7 @@ var CodeMirror = (function() {
209 225
       updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
210 226
                   splitLines(code), top, top);
211 227
       history = new History();
  228
+      updateInput = true;
212 229
     }
213 230
     function getValue(code) {
214 231
       var text = [];
@@ -221,17 +238,17 @@ var CodeMirror = (function() {
221 238
       // Check whether this is a click in a widget
222 239
       for (var n = e_target(e); n != wrapper; n = n.parentNode)
223 240
         if (n.parentNode == code && n != mover) return;
224  
-      var ld = lastDoubleClick; lastDoubleClick = null;
  241
+
225 242
       // First, see if this is a click in the gutter
226 243
       for (var n = e_target(e); n != wrapper; n = n.parentNode)
227 244
         if (n.parentNode == gutterText) {
228 245
           if (options.onGutterClick)
229  
-            options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom);
  246
+            options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom, e);
230 247
           return e_preventDefault(e);
231 248
         }
232 249
 
233 250
       var start = posFromMouse(e);
234  
-      
  251
+
235 252
       switch (e_button(e)) {
236 253
       case 3:
237 254
         if (gecko && !mac) onContextMenu(e);
@@ -246,18 +263,26 @@ var CodeMirror = (function() {
246 263
       if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;}
247 264
 
248 265
       if (!focused) onFocus();
249  
-      e_preventDefault(e);
250  
-      if (ld && +new Date - ld < 400) return selectLine(start.line);
251 266
 
252  
-      setCursor(start.line, start.ch, true);
  267
+      var now = +new Date;
  268
+      if (lastDoubleClick > now - 400) {
  269
+        e_preventDefault(e);
  270
+        return selectLine(start.line);
  271
+      } else if (lastClick > now - 400) {
  272
+        lastDoubleClick = now;
  273
+        e_preventDefault(e);
  274
+        return selectWordAt(start);
  275
+      } else { lastClick = now; }
  276
+
253 277
       var last = start, going;
254  
-      // And then we have to see if it's a drag event, in which case
255  
-      // the dragged-over text must be selected.
256  
-      function end() {
257  
-        focusInput();
258  
-        updateInput = true;
259  
-        move(); up();
  278
+      if (dragAndDrop && !posEq(sel.from, sel.to) &&
  279
+          !posLess(start, sel.from) && !posLess(sel.to, start)) {
  280
+        // Let the drag handler handle this.
  281
+        return;
260 282
       }
  283
+      e_preventDefault(e);
  284
+      setCursor(start.line, start.ch, true);
  285
+
261 286
       function extend(e) {
262 287
         var cur = posFromMouse(e, true);
263 288
         if (cur && !posEq(cur, last)) {
@@ -281,16 +306,11 @@ var CodeMirror = (function() {
281 306
         var cur = posFromMouse(e);
282 307
         if (cur) setSelectionUser(start, cur);
283 308
         e_preventDefault(e);
284  
-        end();
  309
+        focusInput();
  310
+        updateInput = true;
  311
+        move(); up();
285 312
       }), true);
286 313
     }
287  
-    function onDblClick(e) {
288  
-      var pos = posFromMouse(e);
289  
-      if (!pos) return;
290  
-      selectWordAt(pos);
291  
-      e_preventDefault(e);
292  
-      lastDoubleClick = +new Date;
293  
-    }
294 314
     function onDrop(e) {
295 315
       e.preventDefault();
296 316
       var pos = posFromMouse(e, true), files = e.dataTransfer.files;
@@ -315,6 +335,13 @@ var CodeMirror = (function() {
315 335
         catch(e){}
316 336
       }
317 337
     }
  338
+    function onDragStart(e) {
  339
+      var txt = getSelection();
  340
+      // This will reset escapeElement
  341
+      htmlEscape(txt);
  342
+      e.dataTransfer.setDragImage(escapeElement, 0, 0);
  343
+      e.dataTransfer.setData("Text", txt);
  344
+    }
318 345
     function onKeyDown(e) {
319 346
       if (!focused) onFocus();
320 347
 
@@ -340,6 +367,7 @@ var CodeMirror = (function() {
340 367
         if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
341 368
         if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
342 369
       }
  370
+      if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
343 371
 
344 372
       // Key id to use in the movementKeys map. We also pass it to
345 373
       // fastPoll in order to 'self learn'. We need this because
@@ -347,14 +375,16 @@ var CodeMirror = (function() {
347 375
       // its start when it is inverted and a movement key is pressed
348 376
       // (and later restore it again), shouldn't be used for
349 377
       // non-movement keys.
350  
-      curKeyId = (mod ? "c" : "") + code;
351  
-      if (sel.inverted && movementKeys.hasOwnProperty(curKeyId)) {
  378
+      curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
  379
+      if (sel.inverted && movementKeys[curKeyId] === true) {
352 380
         var range = selRange(input);
353 381
         if (range) {
354 382
           reducedSelection = {anchor: range.start};
355 383
           setSelRange(input, range.start, range.start);
356 384
         }
357 385
       }
  386
+      // Don't save the key as a movementkey unless it had a modifier
  387
+      if (!mod && !e.altKey) curKeyId = null;
358 388
       fastPoll(curKeyId);
359 389
     }
360 390
     function onKeyUp(e) {
@@ -566,7 +596,10 @@ var CodeMirror = (function() {
566 596
       function p() {
567 597
         startOperation();
568 598
         var changed = readInput();
569  
-        if (changed == "moved" && keyId) movementKeys[keyId] = true;
  599
+        if (changed && keyId) {
  600
+          if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
  601
+          if (changed == "changed") movementKeys[keyId] = false;
  602
+        }
570 603
         if (!changed && !missed) {missed = true; poll.set(80, p);}
571 604
         else {pollingFast = false; slowPoll();}
572 605
         endOperation();
@@ -663,6 +696,12 @@ var CodeMirror = (function() {
663 696
       if (options.readOnly != "nocursor") input.focus();
664 697
     }
665 698
 
  699
+    function scrollEditorIntoView() {
  700
+      if (!cursor.getBoundingClientRect) return;
  701
+      var rect = cursor.getBoundingClientRect();
  702
+      var winH = window.innerHeight || document.body.offsetHeight || document.documentElement.offsetHeight;
  703
+      if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
  704
+    }
666 705
     function scrollCursorIntoView() {
667 706
       var cursor = localCoords(sel.inverted ? sel.from : sel.to);
668 707
       return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
@@ -675,9 +714,10 @@ var CodeMirror = (function() {
675 714
       else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;}
676 715
 
677 716
       var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
678  
-      if (x1 < screenleft) {
  717
+      var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
  718
+      if (x1 < screenleft + gutterw) {
679 719
         if (x1 < 50) x1 = 0;
680  
-        scroller.scrollLeft = Math.max(0, x1 - 10);
  720
+        scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw);
681 721
         scrolled = true;
682 722
       }
683 723
       else if (x2 > screenw + screenleft) {
@@ -745,6 +785,7 @@ var CodeMirror = (function() {
745 785
       if (domPos != domEnd || pos != to) {
746 786
         changedLines += Math.abs(to - pos);
747 787
         updates.push({from: pos, to: to, domSize: domEnd - domPos, domStart: domPos});
  788
+        if (to - pos != domEnd - domPos) gutterDirty = true;
748 789
       }
749 790
 
750 791
       if (!updates.length) return;
@@ -766,8 +807,8 @@ var CodeMirror = (function() {
766 807
       if (different) {
767 808
         lastHeight = scroller.clientHeight;
768 809
         code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
769  
-        updateGutter();
770 810
       }
  811
+      if (different || gutterDirty) updateGutter();
771 812
 
772 813
       if (maxWidth == null) maxWidth = stringWidth(maxLine);
773 814
       if (maxWidth > scroller.clientWidth) {
@@ -868,13 +909,17 @@ var CodeMirror = (function() {
868 909
       if (pad) firstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
869 910
       gutter.style.display = "";
870 911
       lineSpace.style.marginLeft = gutter.offsetWidth + "px";
  912
+      gutterDirty = false;
871 913
     }
872 914
     function updateCursor() {
873 915
       var head = sel.inverted ? sel.from : sel.to, lh = lineHeight();
874  
-      var x = charX(head.line, head.ch) + "px", y = (head.line - showingFrom) * lh + "px";
875  
-      inputDiv.style.top = (head.line * lh - scroller.scrollTop) + "px";
  916
+      var x = charX(head.line, head.ch);
  917
+      var top = head.line * lh - scroller.scrollTop;
  918
+      inputDiv.style.top = Math.max(Math.min(top, scroller.offsetHeight), 0) + "px";
  919
+      inputDiv.style.left = (x - scroller.scrollLeft) + "px";
876 920
       if (posEq(sel.from, sel.to)) {
877  
-        cursor.style.top = y; cursor.style.left = x;
  921
+        cursor.style.top = (head.line - showingFrom) * lh + "px";
  922
+        cursor.style.left = x + "px";
878 923
         cursor.style.display = "";
879 924
       }
880 925
       else cursor.style.display = "none";
@@ -994,6 +1039,10 @@ var CodeMirror = (function() {
994 1039
       }
995 1040
       return true;
996 1041
     }
  1042
+    function smartHome() {
  1043
+      var firstNonWS = Math.max(0, lines[sel.from.line].text.search(/\S/));
  1044
+      setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
  1045
+    }
997 1046
 
998 1047
     function indentLine(n, how) {
999 1048
       if (how == "smart") {
@@ -1036,7 +1085,7 @@ var CodeMirror = (function() {
1036 1085
     function gutterChanged() {
1037 1086
       var visible = options.gutter || options.lineNumbers;
1038 1087
       gutter.style.display = visible ? "" : "none";
1039  
-      if (visible) updateGutter();
  1088
+      if (visible) gutterDirty = true;
1040 1089
       else lineDiv.parentNode.style.marginLeft = 0;
1041 1090
     }
1042 1091
 
@@ -1073,13 +1122,13 @@ var CodeMirror = (function() {
1073 1122
     function addGutterMarker(line, text, className) {
1074 1123
       if (typeof line == "number") line = lines[clipLine(line)];
1075 1124
       line.gutterMarker = {text: text, style: className};
1076  
-      updateGutter();
  1125
+      gutterDirty = true;
1077 1126
       return line;
1078 1127
     }
1079 1128
     function removeGutterMarker(line) {
1080 1129
       if (typeof line == "number") line = lines[clipLine(line)];
1081 1130
       line.gutterMarker = null;
1082  
-      updateGutter();
  1131
+      gutterDirty = true;
1083 1132
     }
1084 1133
     function setLineClass(line, className) {
1085 1134
       if (typeof line == "number") {
@@ -1190,8 +1239,8 @@ var CodeMirror = (function() {
1190 1239
 
1191 1240
       var oldCSS = input.style.cssText;
1192 1241
       inputDiv.style.position = "absolute";
1193  
-      input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e_pageY(e) - 1) +
1194  
-        "px; left: " + (e_pageX(e) - 1) + "px; z-index: 1000; background: white; " +
  1242
+      input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
  1243
+        "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
1195 1244
         "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
1196 1245
       leaveInputAlone = true;
1197 1246
       var val = input.value = getSelection();
@@ -1206,7 +1255,7 @@ var CodeMirror = (function() {
1206 1255
         prepareInput();
1207 1256
         slowPoll();
1208 1257
       }
1209  
-      
  1258
+
1210 1259
       if (gecko) {
1211 1260
         e_stop(e);
1212 1261
         var mouseup = connect(window, "mouseup", function() {
@@ -1284,7 +1333,7 @@ var CodeMirror = (function() {
1284 1333
         if (line.stateAfter) return search;
1285 1334
         var indented = line.indentation();
1286 1335
         if (minline == null || minindent > indented) {
1287  
-          minline = search;
  1336
+          minline = search - 1;
1288 1337
           minindent = indented;
1289 1338
         }
1290 1339
       }
@@ -1321,25 +1370,26 @@ var CodeMirror = (function() {
1321 1370
         if (state) state = copyState(mode, state);
1322 1371
         else state = startState(mode);
1323 1372
 
1324  
-        var unchanged = 0, compare = mode.compareStates;
  1373
+        var unchanged = 0, compare = mode.compareStates, realChange = false;
1325 1374
         for (var i = start, l = lines.length; i < l; ++i) {
1326 1375
           var line = lines[i], hadState = line.stateAfter;
1327 1376
           if (+new Date > end) {
1328 1377
             work.push(i);
1329 1378
             startWorker(options.workDelay);
1330  
-            changes.push({from: task, to: i + 1});
  1379
+            if (realChange) changes.push({from: task, to: i + 1});
1331 1380
             return;
1332 1381
           }
1333 1382
           var changed = line.highlight(mode, state);
  1383
+          if (changed) realChange = true;
1334 1384
           line.stateAfter = copyState(mode, state);
1335 1385
           if (compare) {
1336 1386
             if (hadState && compare(hadState, state)) break;
1337 1387
           } else {
1338  
-            if (changed || !hadState) unchanged = 0;
  1388
+            if (changed !== false || !hadState) unchanged = 0;
1339 1389
             else if (++unchanged > 3) break;
1340 1390
           }
1341 1391
         }
1342  
-        changes.push({from: task, to: i + 1});
  1392
+        if (realChange) changes.push({from: task, to: i + 1});
1343 1393
       }
1344 1394
       if (foundWork && options.onHighlightComplete)
1345 1395
         options.onHighlightComplete(instance);
@@ -1360,9 +1410,12 @@ var CodeMirror = (function() {
1360 1410
       var reScroll = false;
1361 1411
       if (selectionChanged) reScroll = !scrollCursorIntoView();
1362 1412
       if (changes.length) updateDisplay(changes);
1363  
-      else if (selectionChanged) updateCursor();
  1413
+      else {
  1414
+        if (selectionChanged) updateCursor();
  1415
+        if (gutterDirty) updateGutter();
  1416
+      }
1364 1417
       if (reScroll) scrollCursorIntoView();
1365  
-      if (selectionChanged) restartBlink();
  1418
+      if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
1366 1419
 
1367 1420
       // updateInput can be set to a boolean value to force/prevent an
1368 1421
       // update.
@@ -1525,8 +1578,10 @@ var CodeMirror = (function() {
1525 1578
     onKeyEvent: null,
1526 1579
     lineNumbers: false,
1527 1580
     gutter: false,
  1581
+    fixedGutter: false,
1528 1582
     firstLineNumber: 1,
1529 1583
     readOnly: false,
  1584
+    smartHome: true,
1530 1585
     onChange: null,
1531 1586
     onCursorActivity: null,
1532 1587
     onGutterClick: null,
@@ -1572,7 +1627,7 @@ var CodeMirror = (function() {
1572 1627
   CodeMirror.listMIMEs = function() {
1573 1628
     var list = [];
1574 1629
     for (var m in mimeModes)
1575  
-      if (mimeModes.propertyIsEnumerable(m)) list.push(m);
  1630
+      if (mimeModes.propertyIsEnumerable(m)) list.push({mime: m, mode: mimeModes[m]});
1576 1631
     return list;
1577 1632
   };
1578 1633
 
@@ -1660,7 +1715,7 @@ var CodeMirror = (function() {
1660 1715
       if (ok) {++this.pos; return ch;}
1661 1716
     },
1662 1717
     eatWhile: function(match) {
1663  
-      var start = this.start;
  1718
+      var start = this.pos;
1664 1719
       while (this.eat(match)){}
1665 1720
       return this.pos > start;
1666 1721
     },
@@ -1769,10 +1824,10 @@ var CodeMirror = (function() {
1769 1824
       }
1770 1825
       if (st.length != pos) {st.length = pos; changed = true;}
1771 1826
       if (pos && st[pos-2] != prevWord) changed = true;
1772  
-      // Short lines with simple highlights always count as changed,
1773  
-      // because they are likely to highlight the same way in various
1774  
-      // contexts.
1775  
-      return changed || (st.length < 5 && this.text.length < 10);
  1827
+      // Short lines with simple highlights return null, and are
  1828
+      // counted as changed by the driver because they are likely to
  1829
+      // highlight the same way in various contexts.
  1830
+      return changed || (st.length < 5 && this.text.length < 10 ? null : false);
1776 1831
     },
1777 1832
     // Fetch the parser token for a given character. Useful for hacks
1778 1833
     // that want to inspect the mode state (say, for completion).
@@ -1930,16 +1985,6 @@ var CodeMirror = (function() {
1930 1985
     else if (e.button & 2) return 3;
1931 1986
     else if (e.button & 4) return 2;
1932 1987
   }
1933  
-  function e_pageX(e) {
1934  
-    if (e.pageX != null) return e.pageX;
1935  
-    var doc = e_target(e).ownerDocument;
1936  
-    return e.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft;
1937  
-  }
1938  
-  function e_pageY(e) {
1939  
-    if (e.pageY != null) return e.pageY;
1940  
-    var doc = e_target(e).ownerDocument;
1941  
-    return e.clientY + doc.body.scrollTop + doc.documentElement.scrollTop;
1942  
-  }
1943 1988
 
1944 1989
   // Event handler registration. If disconnect is true, it'll return a
1945 1990
   // function that unregisters the handler.
@@ -1965,6 +2010,15 @@ var CodeMirror = (function() {
1965 2010
     pre.innerHTML = " "; return !pre.innerHTML;
1966 2011
   })();
1967 2012
 
  2013
+  // Detect drag-and-drop
  2014
+  var dragAndDrop = (function() {
  2015
+    // IE8 has ondragstart and ondrop properties, but doesn't seem to
  2016
+    // actually support ondragstart the way it's supposed to work.
  2017
+    if (/MSIE [1-8]\b/.test(navigator.userAgent)) return false;
  2018
+    var div = document.createElement('div');
  2019
+    return "ondragstart" in div && "ondrop" in div;
  2020
+  })();
  2021
+
1968 2022
   var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
1969 2023
   var ie = /MSIE \d/.test(navigator.userAgent);
1970 2024
   var safari = /Apple Computer/.test(navigator.vendor);
@@ -2140,5 +2194,4 @@ var CodeMirror = (function() {
2140 2194
   CodeMirror.defineMIME("text/plain", "null");
2141 2195
 
2142 2196
   return CodeMirror;
2143  
-})()
2144  
-;
  2197
+})();
2  ...ml/notebook/static/codemirror-2.12/lib/overlay.js → ...nd/html/notebook/static/codemirror/lib/overlay.js
@@ -42,7 +42,7 @@ CodeMirror.overlayParser = function(base, overlay, combine) {
42 42
       if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
43 43
       else return state.overlayCur;
44 44
     },
45  
-    
  45
+
46 46
     indent: function(state, textAfter) {
47 47
       return base.indent(state.base, textAfter);
48 48
     },
0  ...ml/notebook/static/codemirror-2.12/lib/runmode.js → ...nd/html/notebook/static/codemirror/lib/runmode.js
File renamed without changes
6  ...l/notebook/static/codemirror-2.12/mode/css/css.js → ...d/html/notebook/static/codemirror/mode/css/css.js
@@ -4,7 +4,7 @@ CodeMirror.defineMode("css", function(config) {
4 4
 
5 5
   function tokenBase(stream, state) {
6 6
     var ch = stream.next();
7  
-    if (ch == "@") {stream.eatWhile(/\w/); return ret("meta", stream.current());}
  7
+    if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
8 8
     else if (ch == "/" && stream.eat("*")) {
9 9
       state.tokenize = tokenCComment;
10 10
       return tokenCComment(stream, state);
@@ -20,7 +20,7 @@ CodeMirror.defineMode("css", function(config) {
20 20
       return state.tokenize(stream, state);
21 21
     }
22 22
     else if (ch == "#") {
23  
-      stream.eatWhile(/\w/);
  23
+      stream.eatWhile(/[\w\\\-]/);
24 24
       return ret("atom", "hash");
25 25
     }
26 26
     else if (ch == "!") {
@@ -38,7 +38,7 @@ CodeMirror.defineMode("css", function(config) {
38 38
       return ret(null, ch);
39 39
     }
40 40
     else {
41  
-      stream.eatWhile(/[\w\\\-_]/);
  41
+      stream.eatWhile(/[\w\\\-]/);
42 42
       return ret("variable", "variable");
43 43
     }
44 44
   }
0  ...tebook/static/codemirror-2.12/mode/css/index.html → ...ml/notebook/static/codemirror/mode/css/index.html
File renamed without changes
0  ...tatic/codemirror-2.12/mode/htmlmixed/htmlmixed.js → ...ook/static/codemirror/mode/htmlmixed/htmlmixed.js
File renamed without changes
0  .../static/codemirror-2.12/mode/htmlmixed/index.html → ...ebook/static/codemirror/mode/htmlmixed/index.html
File renamed without changes
0  ...static/codemirror-2.12/mode/javascript/index.html → ...book/static/codemirror/mode/javascript/index.html
File renamed without changes
8  ...tic/codemirror-2.12/mode/javascript/javascript.js → ...k/static/codemirror/mode/javascript/javascript.js
@@ -52,7 +52,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
52 52
     else if (ch == "0" && stream.eat(/x/i)) {
53 53
       stream.eatWhile(/[\da-f]/i);
54 54
       return ret("number", "number");
55  
-    }      
  55
+    }
56 56
     else if (/\d/.test(ch)) {
57 57
       stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
58 58
       return ret("number", "number");
@@ -75,6 +75,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
75 75
         return ret("operator", null, stream.current());
76 76
       }
77 77
     }
  78
+    else if (ch == "#") {
  79
+        stream.skipToEnd();
  80
+        return ret("error", "error");
  81
+    }
78 82
     else if (isOperatorChar.test(ch)) {
79 83
       stream.eatWhile(isOperatorChar);
80 84
       return ret("operator", null, stream.current());
@@ -130,7 +134,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
130 134
     // Communicate our context to the combinators.
131 135
     // (Less wasteful than consing up a hundred closures on every call.)
132 136
     cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
133  
-  
  137
+
134 138
     if (!state.lexical.hasOwnProperty("align"))
135 139
       state.lexical.align = true;
136 140
 
340  IPython/frontend/html/notebook/static/codemirror/mode/markdown/index.html
... ...
@@ -0,0 +1,340 @@
  1
+<!doctype html>
  2
+<html>
  3
+  <head>
  4
+    <title>CodeMirror 2: Markdown mode</title>
  5
+    <link rel="stylesheet" href="../../lib/codemirror.css">
  6
+    <script src="../../lib/codemirror.js"></script>
  7
+    <script src="../xml/xml.js"></script>
  8
+    <script src="markdown.js"></script>
  9
+    <link rel="stylesheet" href="../../theme/default.css">
  10
+    <link rel="stylesheet" href="markdown.css">
  11
+    <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
  12
+    <link rel="stylesheet" href="../../css/docs.css">
  13
+  </head>
  14
+  <body>
  15
+    <h1>CodeMirror 2: Markdown mode</h1>
  16
+
  17
+<!-- source: http://daringfireball.net/projects/markdown/basics.text -->
  18
+<form><textarea id="code" name="code">
  19
+Markdown: Basics
  20
+================
  21
+
  22
+&lt;ul id="ProjectSubmenu"&gt;
  23
+    &lt;li&gt;&lt;a href="/projects/markdown/" title="Markdown Project Page"&gt;Main&lt;/a&gt;&lt;/li&gt;
  24
+    &lt;li&gt;&lt;a class="selected" title="Markdown Basics"&gt;Basics&lt;/a&gt;&lt;/li&gt;
  25
+    &lt;li&gt;&lt;a href="/projects/markdown/syntax" title="Markdown Syntax Documentation"&gt;Syntax&lt;/a&gt;&lt;/li&gt;
  26
+    &lt;li&gt;&lt;a href="/projects/markdown/license" title="Pricing and License Information"&gt;License&lt;/a&gt;&lt;/li&gt;
  27
+    &lt;li&gt;&lt;a href="/projects/markdown/dingus" title="Online Markdown Web Form"&gt;Dingus&lt;/a&gt;&lt;/li&gt;
  28
+&lt;/ul&gt;
  29
+
  30
+
  31
+Getting the Gist of Markdown's Formatting Syntax
  32
+------------------------------------------------
  33
+
  34
+This page offers a brief overview of what it's like to use Markdown.
  35
+The [syntax page] [s] provides complete, detailed documentation for
  36
+every feature, but Markdown should be very easy to pick up simply by
  37
+looking at a few examples of it in action. The examples on this page
  38
+are written in a before/after style, showing example syntax and the
  39
+HTML output produced by Markdown.
  40
+
  41
+It's also helpful to simply try Markdown out; the [Dingus] [d] is a
  42
+web application that allows you type your own Markdown-formatted text
  43
+and translate it to XHTML.
  44
+
  45
+**Note:** This document is itself written using Markdown; you
  46
+can [see the source for it by adding '.text' to the URL] [src].
  47
+
  48
+  [s]: /projects/markdown/syntax  "Markdown Syntax"
  49
+  [d]: /projects/markdown/dingus  "Markdown Dingus"
  50
+  [src]: /projects/markdown/basics.text
  51
+
  52
+
  53
+## Paragraphs, Headers, Blockquotes ##
  54
+
  55
+A paragraph is simply one or more consecutive lines of text, separated
  56
+by one or more blank lines. (A blank line is any line that looks like
  57
+a blank line -- a line containing nothing but spaces or tabs is
  58
+considered blank.) Normal paragraphs should not be indented with
  59
+spaces or tabs.
  60
+
  61
+Markdown offers two styles of headers: *Setext* and *atx*.
  62
+Setext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by
  63
+"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
  64
+To create an atx-style header, you put 1-6 hash marks (`#`) at the
  65
+beginning of the line -- the number of hashes equals the resulting
  66
+HTML header level.
  67
+
  68
+Blockquotes are indicated using email-style '`&gt;`' angle brackets.
  69
+
  70
+Markdown:
  71
+
  72
+    A First Level Header
  73
+    ====================
  74
+
  75
+    A Second Level Header
  76
+    ---------------------
  77
+
  78
+    Now is the time for all good men to come to
  79
+    the aid of their country. This is just a
  80
+    regular paragraph.
  81
+
  82
+    The quick brown fox jumped over the lazy
  83
+    dog's back.
  84
+
  85
+    ### Header 3
  86
+
  87
+    &gt; This is a blockquote.
  88
+    &gt;
  89
+    &gt; This is the second paragraph in the blockquote.
  90
+    &gt;
  91
+    &gt; ## This is an H2 in a blockquote
  92
+
  93
+
  94
+Output:
  95
+
  96
+    &lt;h1&gt;A First Level Header&lt;/h1&gt;
  97
+
  98
+    &lt;h2&gt;A Second Level Header&lt;/h2&gt;
  99
+
  100
+    &lt;p&gt;Now is the time for all good men to come to
  101
+    the aid of their country. This is just a
  102
+    regular paragraph.&lt;/p&gt;
  103
+
  104
+    &lt;p&gt;The quick brown fox jumped over the lazy
  105
+    dog's back.&lt;/p&gt;
  106
+
  107
+    &lt;h3&gt;Header 3&lt;/h3&gt;
  108
+
  109
+    &lt;blockquote&gt;
  110
+        &lt;p&gt;This is a blockquote.&lt;/p&gt;
  111
+
  112
+        &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
  113
+
  114
+        &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
  115
+    &lt;/blockquote&gt;
  116
+
  117
+
  118
+
  119
+### Phrase Emphasis ###
  120
+
  121
+Markdown uses asterisks and underscores to indicate spans of emphasis.
  122
+
  123
+Markdown:
  124
+
  125
+    Some of these words *are emphasized*.
  126
+    Some of these words _are emphasized also_.
  127
+
  128
+    Use two asterisks for **strong emphasis**.
  129
+    Or, if you prefer, __use two underscores instead__.
  130
+
  131
+Output:
  132
+
  133
+    &lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
  134
+    Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
  135
+
  136
+    &lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
  137
+    Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
  138
+
  139
+
  140
+
  141
+## Lists ##
  142
+
  143
+Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
  144
+`+`, and `-`) as list markers. These three markers are
  145
+interchangable; this:
  146
+
  147
+    *   Candy.
  148
+    *   Gum.
  149
+    *   Booze.
  150
+
  151
+this:
  152
+
  153
+    +   Candy.
  154
+    +   Gum.
  155
+    +   Booze.
  156
+
  157
+and this:
  158
+
  159
+    -   Candy.
  160
+    -   Gum.
  161
+    -   Booze.
  162
+
  163
+all produce the same output:
  164
+
  165
+    &lt;ul&gt;
  166
+    &lt;li&gt;Candy.&lt;/li&gt;
  167
+    &lt;li&gt;Gum.&lt;/li&gt;
  168
+    &lt;li&gt;Booze.&lt;/li&gt;
  169
+    &lt;/ul&gt;
  170
+
  171
+Ordered (numbered) lists use regular numbers, followed by periods, as
  172
+list markers:
  173
+
  174
+    1.  Red
  175
+    2.  Green
  176
+    3.  Blue
  177
+
  178
+Output:
  179
+
  180
+    &lt;ol&gt;
  181
+    &lt;li&gt;Red&lt;/li&gt;
  182
+    &lt;li&gt;Green&lt;/li&gt;
  183
+    &lt;li&gt;Blue&lt;/li&gt;
  184
+    &lt;/ol&gt;
  185
+
  186
+If you put blank lines between items, you'll get `&lt;p&gt;` tags for the
  187
+list item text. You can create multi-paragraph list items by indenting
  188
+the paragraphs by 4 spaces or 1 tab:
  189
+
  190
+    *   A list item.
  191
+
  192
+        With multiple paragraphs.
  193
+
  194
+    *   Another item in the list.
  195
+
  196
+Output:
  197
+
  198
+    &lt;ul&gt;
  199
+    &lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
  200
+    &lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
  201
+    &lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
  202
+    &lt;/ul&gt;
  203
+
  204
+
  205
+
  206
+### Links ###
  207
+
  208
+Markdown supports two styles for creating links: *inline* and
  209
+*reference*. With both styles, you use square brackets to delimit the
  210
+text you want to turn into a link.
  211
+
  212
+Inline-style links use parentheses immediately after the link text.
  213
+For example:
  214
+
  215
+    This is an [example link](http://example.com/).
  216
+
  217
+Output: