Вход Регистрация
Файл: wysiwyg/live/scripts/common/codemirror/lib/codemirror.js
Строк: 5062
<?php
// CodeMirror version 2.2
//
// All functions that need access to the editor's state live inside
// the CodeMirror function. Below that, at the bottom of the file,
// some utilities are defined.

// CodeMirror is the only global var we claim
var CodeMirror = (function() {
  
// This is the function that produces an editor instance. It's
  // closure is used to store the editor state.
  
function CodeMirror(placegivenOptions) {
    
// Determine effective options based on given values and defaults.
    
var options = {}, defaults CodeMirror.defaults;
    for (var 
opt in defaults)
      if (
defaults.hasOwnProperty(opt))
        
options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions defaults)[opt];

    var 
targetDocument options["document"];
    
// The element in which the editor lives.
    
var wrapper targetDocument.createElement("div");
    
wrapper.className "CodeMirror" + (options.lineWrapping " CodeMirror-wrap" "");
    
// This mess creates the base DOM structure for the editor.
    
wrapper.innerHTML =
      
'<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' // Wraps and hides input textarea
        
'<textarea style="position: absolute; padding: 0; width: 1px;" wrap="off" ' +
          
'autocorrect="off" autocapitalize="off"></textarea></div>' +
      
'<div class="CodeMirror-scroll" tabindex="-1">' +
        
'<div style="position: relative">' // Set to the height of the text, causes scrolling
          
'<div style="position: relative">' // Moved around its parent to cover visible view
            
'<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
            
// Provides positioning relative to (visible) text origin
            
'<div class="CodeMirror-lines"><div style="position: relative">' +
              
'<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden"></div>' +
              
'<pre class="CodeMirror-cursor">&#160;</pre>' // Absolutely positioned blinky cursor
              
'<div></div>' // This DIV contains the actual code
            
'</div></div></div></div></div>';
    if (
place.appendChildplace.appendChild(wrapper); else place(wrapper);
    
// I've never seen more elegant code in my life.
    
var inputDiv wrapper.firstChildinput inputDiv.firstChild,
        
scroller wrapper.lastChildcode scroller.firstChild,
        
mover code.firstChildgutter mover.firstChildgutterText gutter.firstChild,
        
lineSpace gutter.nextSibling.firstChildmeasure lineSpace.firstChild,
        
cursor measure.nextSiblinglineDiv cursor.nextSibling;
    
themeChanged();
    
// Needed to hide big blue blinking cursor on Mobile Safari
    
if (/AppleWebKit/.test(navigator.userAgent) && /Mobile/w+/.test(navigator.userAgent)) input.style.width "0px";
    if (!
webkitlineSpace.draggable true;
    if (
options.tabindex != nullinput.tabIndex options.tabindex;
    if (!
options.gutter && !options.lineNumbersgutter.style.display "none";

    
// Check for problem with IE innerHTML not working when we have a
    // P (or similar) parent node.
    
try { stringWidth("x"); }
    catch (
e) {
      if (
e.message.match(/runtime/i))
        
= new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
      throw 
e;
    }

    
// Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
    
var poll = new Delayed(), highlight = new Delayed(), blinker;

    
// mode holds a mode API object. doc is the tree of Line objects,
    // work an array of lines that should be parsed, and history the
    // undo history (instance of History constructor).
    
var modedoc = new BranchChunk([new LeafChunk([new Line("")])]), workfocused;
    
loadMode();
    
// The selection. These are always maintained to point at valid
    // positions. Inverted is used to remember that the user is
    // selecting bottom-to-top.
    
var sel = {from: {line0ch0}, to: {line0ch0}, invertedfalse};
    
// Selection-related flags. shiftSelecting obviously tracks
    // whether the user is holding shift.
    
var shiftSelectinglastClicklastDoubleClickdraggingTextoverwrite false;
    
// Variables used by startOperation/endOperation to track what
    // happened during the operation.
    
var updateInputuserSelChangechangestextChangedselectionChangedleaveInputAlone,
        
gutterDirtycallbacks;
    
// Current visible range (may be bigger than the view window).
    
var displayOffset 0showingFrom 0showingTo 0lastSizeC 0;
    
// bracketHighlighted is used to remember that a backet has been
    // marked.
    
var bracketHighlighted;
    
// Tracks the maximum line length so that the horizontal scrollbar
    // can be kept static when scrolling.
    
var maxLine ""maxWidthtabText computeTabText();

    
// Initialize the content.
    
operation(function(){setValue(options.value || ""); updateInput false;})();
    var 
history = new History();

    
// Register our event handlers.
    
connect(scroller"mousedown"operation(onMouseDown));
    
connect(scroller"dblclick"operation(onDoubleClick));
    
connect(lineSpace"dragstart"onDragStart);
    
connect(lineSpace"selectstart"e_preventDefault);
    
// Gecko browsers fire contextmenu *after* opening the menu, at
    // which point we can't mess with it anymore. Context menu is
    // handled in onMouseDown for Gecko.
    
if (!geckoconnect(scroller"contextmenu"onContextMenu);
    
connect(scroller"scroll", function() {
      
updateDisplay([]);
      if (
options.fixedGuttergutter.style.left scroller.scrollLeft "px";
      if (
options.onScrolloptions.onScroll(instance);
    });
    
connect(window"resize", function() {updateDisplay(true);});
    
connect(input"keyup"operation(onKeyUp));
    
connect(input"input"fastPoll);
    
connect(input"keydown"operation(onKeyDown));
    
connect(input"keypress"operation(onKeyPress));
    
connect(input"focus"onFocus);
    
connect(input"blur"onBlur);

    
connect(scroller"dragenter"e_stop);
    
connect(scroller"dragover"e_stop);
    
connect(scroller"drop"operation(onDrop));
    
connect(scroller"paste", function(){focusInput(); fastPoll();});
    
connect(input"paste"fastPoll);
    
connect(input"cut"operation(function(){replaceSelection("");}));

    
// IE throws unspecified error in certain cases, when
    // trying to access activeElement before onload
    
var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
    if (
hasFocussetTimeout(onFocus20);
    else 
onBlur();

    function 
isLine(l) {return >= && doc.size;}
    
// The instance object that we'll return. Mostly calls out to
    // local functions in the CodeMirror function. Some do some extra
    // range checking and/or clipping. operation is used to wrap the
    // call so that changes it makes are tracked, and the display is
    // updated afterwards.
    
var instance wrapper.CodeMirror = {
      
getValuegetValue,
      
setValueoperation(setValue),
      
getSelectiongetSelection,
      
replaceSelectionoperation(replaceSelection),
      
focus: function(){focusInput(); onFocus(); fastPoll();},
      
setOption: function(optionvalue) {
        var 
oldVal options[option];
        
options[option] = value;
        if (
option == "mode" || option == "indentUnit"loadMode();
        else if (
option == "readOnly" && value) {onBlur(); input.blur();}
        else if (
option == "theme"themeChanged();
        else if (
option == "lineWrapping" && oldVal != valueoperation(wrappingChanged)();
        else if (
option == "tabSize"operation(tabsChanged)();
        if (
option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme")
          
operation(gutterChanged)();
      },
      
getOption: function(option) {return options[option];},
      
undooperation(undo),
      
redooperation(redo),
      
indentLineoperation(function(ndir) {
        if (
isLine(n)) indentLine(ndir == null "smart" dir "add" "subtract");
      }),
      
indentSelectionoperation(indentSelected),
      
historySize: function() {return {undohistory.done.lengthredohistory.undone.length};},
      
clearHistory: function() {history = new History();},
      
matchBracketsoperation(function(){matchBrackets(true);}),
      
getTokenAtoperation(function(pos) {
        
pos clipPos(pos);
        return 
getLine(pos.line).getTokenAt(modegetStateBefore(pos.line), pos.ch);
      }),
      
getStateAfter: function(line) {
        
line clipLine(line == null doc.size 1line);
        return 
getStateBefore(line 1);
      },
      
cursorCoords: function(start){
        if (
start == nullstart sel.inverted;
        return 
pageCoords(start sel.from sel.to);
      },
      
charCoords: function(pos){return pageCoords(clipPos(pos));},
      
coordsChar: function(coords) {
        var 
off eltOffset(lineSpace);
        return 
coordsChar(coords.off.leftcoords.off.top);
      },
      
markTextoperation(markText),
      
setBookmarksetBookmark,
      
setMarkeroperation(addGutterMarker),
      
clearMarkeroperation(removeGutterMarker),
      
setLineClassoperation(setLineClass),
      
hideLineoperation(function(h) {return setLineHidden(htrue);}),
      
showLineoperation(function(h) {return setLineHidden(hfalse);}),
      
onDeleteLine: function(linef) {
        if (
typeof line == "number") {
          if (!
isLine(line)) return null;
          
line getLine(line);
        }
        (
line.handlers || (line.handlers = [])).push(f);
        return 
line;
      },
      
lineInfolineInfo,
      
addWidget: function(posnodescrollverthoriz) {
        
pos localCoords(clipPos(pos));
        var 
top pos.yBotleft pos.x;
        
node.style.position "absolute";
        
code.appendChild(node);
        if (
vert == "over"top pos.y;
        else if (
vert == "near") {
          var 
vspace Math.max(scroller.offsetHeightdoc.height textHeight()),
              
hspace Math.max(code.clientWidthlineSpace.clientWidth) - paddingLeft();
          if (
pos.yBot node.offsetHeight vspace && pos.node.offsetHeight)
            
top pos.node.offsetHeight;
          if (
left node.offsetWidth hspace)
            
left hspace node.offsetWidth;
        }
        
node.style.top = (top paddingTop()) + "px";
        
node.style.left node.style.right "";
        if (
horiz == "right") {
          
left code.clientWidth node.offsetWidth;
          
node.style.right "0px";
        } else {
          if (
horiz == "left"left 0;
          else if (
horiz == "middle"left = (code.clientWidth node.offsetWidth) / 2;
          
node.style.left = (left paddingLeft()) + "px";
        }
        if (
scroll)
          
scrollIntoView(lefttopleft node.offsetWidthtop node.offsetHeight);
      },

      
lineCount: function() {return doc.size;},
      
clipPosclipPos,
      
getCursor: function(start) {
        if (
start == nullstart sel.inverted;
        return 
copyPos(start sel.from sel.to);
      },
      
somethingSelected: function() {return !posEq(sel.fromsel.to);},
      
setCursoroperation(function(linechuser) {
        if (
ch == null && typeof line.line == "number"setCursor(line.lineline.chuser);
        else 
setCursor(linechuser);
      }),
      
setSelectionoperation(function(fromtouser) {
        (
user setSelectionUser setSelection)(clipPos(from), clipPos(to || from));
      }),
      
getLine: function(line) {if (isLine(line)) return getLine(line).text;},
      
getLineHandle: function(line) {if (isLine(line)) return getLine(line);},
      
setLineoperation(function(linetext) {
        if (
isLine(line)) replaceRange(text, {linelinech0}, {linelinechgetLine(line).text.length});
      }),
      
removeLineoperation(function(line) {
        if (
isLine(line)) replaceRange("", {linelinech0}, clipPos({lineline+1ch0}));
      }),
      
replaceRangeoperation(replaceRange),
      
getRange: function(fromto) {return getRange(clipPos(from), clipPos(to));},

      
execCommand: function(cmd) {return commands[cmd](instance);},
      
// Stuff used by commands, probably not much use to outside code.
      
moveHoperation(moveH),
      
deleteHoperation(deleteH),
      
moveVoperation(moveV),
      
toggleOverwrite: function() {overwrite = !overwrite;},

      
posFromIndex: function(off) {
        var 
lineNo 0ch;
        
doc.iter(0doc.size, function(line) {
          var 
sz line.text.length 1;
          if (
sz off) { ch off; return true; }
          
off -= sz;
          ++
lineNo;
        });
        return 
clipPos({linelineNochch});
      },
      
indexFromPos: function (coords) {
        if (
coords.line || coords.ch 0) return 0;
        var 
index coords.ch;
        
doc.iter(0coords.line, function (line) {
          
index += line.text.length 1;
        });
        return 
index;
      },

      
operation: function(f){return operation(f)();},
      
refresh: function(){updateDisplay(true);},
      
getInputField: function(){return input;},
      
getWrapperElement: function(){return wrapper;},
      
getScrollerElement: function(){return scroller;},
      
getGutterElement: function(){return gutter;}
    };

    function 
getLine(n) { return getLineAt(docn); }
    function 
updateLineHeight(lineheight) {
      
gutterDirty true;
      var 
diff height line.height;
      for (var 
linenn.parentn.height += diff;
    }

    function 
setValue(code) {
      var 
top = {line0ch0};
      
updateLines(top, {linedoc.size 1chgetLine(doc.size-1).text.length},
                  
splitLines(code), toptop);
      
updateInput true;
    }
    function 
getValue(code) {
      var 
text = [];
      
doc.iter(0doc.size, function(line) { text.push(line.text); });
      return 
text.join("n");
    }

    function 
onMouseDown(e) {
      
setShift(e.shiftKey);
      
// Check whether this is a click in a widget
      
for (var e_target(e); != wrappern.parentNode)
        if (
n.parentNode == code && != mover) return;

      
// See if this is a click in the gutter
      
for (var e_target(e); != wrappern.parentNode)
        if (
n.parentNode == gutterText) {
          if (
options.onGutterClick)
            
options.onGutterClick(instanceindexOf(gutterText.childNodesn) + showingFrome);
          return 
e_preventDefault(e);
        }

      var 
start posFromMouse(e);

      switch (
e_button(e)) {
      case 
3:
        if (
gecko && !maconContextMenu(e);
        return;
      case 
2:
        if (
startsetCursor(start.linestart.chtrue);
        return;
      }
      
// For button 1, if it was clicked inside the editor
      // (posFromMouse returning non-null), we have to adjust the
      // selection.
      
if (!start) {if (e_target(e) == scrollere_preventDefault(e); return;}

      if (!
focusedonFocus();

      var 
now = +new Date;
      if (
lastDoubleClick && lastDoubleClick.time now 400 && posEq(lastDoubleClick.posstart)) {
        
e_preventDefault(e);
        
setTimeout(focusInput20);
        return 
selectLine(start.line);
      } else if (
lastClick && lastClick.time now 400 && posEq(lastClick.posstart)) {
        
lastDoubleClick = {timenowposstart};
        
e_preventDefault(e);
        return 
selectWordAt(start);
      } else { 
lastClick = {timenowposstart}; }

      var 
last startgoing;
      if (
dragAndDrop && !posEq(sel.fromsel.to) &&
          !
posLess(startsel.from) && !posLess(sel.tostart)) {
        
// Let the drag handler handle this.
        
if (webkitlineSpace.draggable true;
        var 
up connect(targetDocument"mouseup"operation(function(e2) {
          if (
webkitlineSpace.draggable false;
          
draggingText false;
          
up();
          if (
Math.abs(e.clientX e2.clientX) + Math.abs(e.clientY e2.clientY) < 10) {
            
e_preventDefault(e2);
            
setCursor(start.linestart.chtrue);
            
focusInput();
          }
        }), 
true);
        
draggingText true;
        return;
      }
      
e_preventDefault(e);
      
setCursor(start.linestart.chtrue);

      function 
extend(e) {
        var 
cur posFromMouse(etrue);
        if (
cur && !posEq(curlast)) {
          if (!
focusedonFocus();
          
last cur;
          
setSelectionUser(startcur);
          
updateInput false;
          var 
visible visibleLines();
          if (
cur.line >= visible.to || cur.line visible.from)
            
going setTimeout(operation(function(){extend(e);}), 150);
        }
      }

      var 
move connect(targetDocument"mousemove"operation(function(e) {
        
clearTimeout(going);
        
e_preventDefault(e);
        
extend(e);
      }), 
true);
      var 
up connect(targetDocument"mouseup"operation(function(e) {
        
clearTimeout(going);
        var 
cur posFromMouse(e);
        if (
cursetSelectionUser(startcur);
        
e_preventDefault(e);
        
focusInput();
        
updateInput true;
        
move(); up();
      }), 
true);
    }
    function 
onDoubleClick(e) {
      for (var 
e_target(e); != wrappern.parentNode)
        if (
n.parentNode == gutterText) return e_preventDefault(e);
      var 
start posFromMouse(e);
      if (!
start) return;
      
lastDoubleClick = {time: +new Dateposstart};
      
e_preventDefault(e);
      
selectWordAt(start);
    }
    function 
onDrop(e) {
      
e.preventDefault();
      var 
pos posFromMouse(etrue), files e.dataTransfer.files;
      if (!
pos || options.readOnly) return;
      if (
files && files.length && window.FileReader && window.File) {
        function 
loadFile(filei) {
          var 
reader = new FileReader;
          
reader.onload = function() {
            
text[i] = reader.result;
            if (++
read == n) {
          
pos clipPos(pos);
          
operation(function() {
                var 
end replaceRange(text.join(""), pospos);
                
setSelectionUser(posend);
              })();
        }
          };
          
reader.readAsText(file);
        }
        var 
files.lengthtext = Array(n), read 0;
        for (var 
0n; ++iloadFile(files[i], i);
      }
      else {
        try {
          var 
text e.dataTransfer.getData("Text");
          if (
text) {
        var 
end replaceRange(textpospos);
        var 
curFrom sel.fromcurTo sel.to;
        
setSelectionUser(posend);
            if (
draggingTextreplaceRange(""curFromcurTo);
        
focusInput();
      }
        }
        catch(
e){}
      }
    }
    function 
onDragStart(e) {
      var 
txt getSelection();
      
// This will reset escapeElement
      
htmlEscape(txt);
      
e.dataTransfer.setDragImage(escapeElement00);
      
e.dataTransfer.setData("Text"txt);
    }
    function 
handleKeyBinding(e) {
      var 
name keyNames[e.keyCode], next keyMap[options.keyMap].autobounddropShift;
      if (
name == null || e.altGraphKey) {
        if (
nextoptions.keyMap next;
        return 
null;
      }
      if (
e.altKeyname "Alt-" name;
      if (
e.ctrlKeyname "Ctrl-" name;
      if (
e.metaKeyname "Cmd-" name;
      if (
e.shiftKey && (bound lookupKey("Shift-" nameoptions.extraKeysoptions.keyMap))) {
        
dropShift true;
      } else {
        
bound lookupKey(nameoptions.extraKeysoptions.keyMap);
      }
      if (
typeof bound == "string") {
        if (
commands.propertyIsEnumerable(bound)) bound commands[bound];
        else 
bound null;
      }
      if (
next && (bound || !isModifierKey(e))) options.keyMap next;
      if (!
bound) return false;
      if (
dropShift) {
        var 
prevShift shiftSelecting;
        
shiftSelecting null;
        
bound(instance);
        
shiftSelecting prevShift;
      } else 
bound(instance);
      
e_preventDefault(e);
      return 
true;
    }
    var 
lastStoppedKey null;
    function 
onKeyDown(e) {
      if (!
focusedonFocus();
      var 
code e.keyCode;
      
// IE does strange things with escape.
      
if (ie && code == 27) { e.returnValue false; }
      
setShift(code == 16 || e.shiftKey);
      
// First give onKeyEvent option a chance to handle this.
      
if (options.onKeyEvent && options.onKeyEvent(instanceaddStop(e))) return;
      var 
handled handleKeyBinding(e);
      if (
window.opera) {
        
lastStoppedKey handled e.keyCode null;
        
// Opera has no cut event... we try to at least catch the key combo
        
if (!handled && (mac e.metaKey e.ctrlKey) && e.keyCode == 88)
          
replaceSelection("");
      }
    }
    function 
onKeyPress(e) {
      if (
window.opera && e.keyCode == lastStoppedKey) {lastStoppedKey nulle_preventDefault(e); return;}
      if (
options.onKeyEvent && options.onKeyEvent(instanceaddStop(e))) return;
      if (
window.opera && !e.which && handleKeyBinding(e)) return;
      if (
options.electricChars && mode.electricChars) {
        var 
ch String.fromCharCode(e.charCode == null e.keyCode e.charCode);
        if (
mode.electricChars.indexOf(ch) > -1)
          
setTimeout(operation(function() {indentLine(sel.to.line"smart");}), 75);
      }
      
fastPoll();
    }
    function 
onKeyUp(e) {
      if (
options.onKeyEvent && options.onKeyEvent(instanceaddStop(e))) return;
      if (
e.keyCode == 16shiftSelecting null;
    }

    function 
onFocus() {
      if (
options.readOnly) return;
      if (!
focused) {
        if (
options.onFocusoptions.onFocus(instance);
        
focused true;
        if (
wrapper.className.search(/bCodeMirror-focusedb/) == -1)
          
wrapper.className += " CodeMirror-focused";
        if (!
leaveInputAloneresetInput(true);
      }
      
slowPoll();
      
restartBlink();
    }
    function 
onBlur() {
      if (
focused) {
        if (
options.onBluroptions.onBlur(instance);
        
focused false;
        
wrapper.className wrapper.className.replace(" CodeMirror-focused""");
      }
      
clearInterval(blinker);
      
setTimeout(function() {if (!focusedshiftSelecting null;}, 150);
    }

    
// Replace the range from from to to by the strings in newText.
    // Afterwards, set the selection to selFrom, selTo.
    
function updateLines(fromtonewTextselFromselTo) {
      if (
history) {
        var 
old = [];
        
doc.iter(from.lineto.line 1, function(line) { old.push(line.text); });
        
history.addChange(from.linenewText.lengthold);
        while (
history.done.length options.undoDepthhistory.done.shift();
      }
      
updateLinesNoUndo(fromtonewTextselFromselTo);
    }
    function 
unredoHelper(fromto) {
      var 
change from.pop();
      if (
change) {
        var 
replaced = [], end change.start change.added;
        
doc.iter(change.startend, function(line) { replaced.push(line.text); });
        
to.push({startchange.startaddedchange.old.lengtholdreplaced});
        var 
pos clipPos({linechange.start change.old.length 1,
                           
cheditEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
        
updateLinesNoUndo({linechange.startch0}, {lineend 1chgetLine(end-1).text.length}, change.oldpospos);
        
updateInput true;
      }
    }
    function 
undo() {unredoHelper(history.donehistory.undone);}
    function 
redo() {unredoHelper(history.undonehistory.done);}

    function 
updateLinesNoUndo(fromtonewTextselFromselTo) {
      var 
recomputeMaxLength falsemaxLineLength maxLine.length;
      if (!
options.lineWrapping)
        
doc.iter(from.lineto.line, function(line) {
          if (
line.text.length == maxLineLength) {recomputeMaxLength true; return true;}
        });
      if (
from.line != to.line || newText.length 1gutterDirty true;

      var 
nlines to.line from.linefirstLine getLine(from.line), lastLine getLine(to.line);
      
// First adjust the line structure, taking some care to leave highlighting intact.
      
if (from.ch == && to.ch == && newText[newText.length 1] == "") {
        
// This is a whole-line replace. Treated specially to make
        // sure line objects move the way they are supposed to.
        
var added = [], prevLine null;
        if (
from.line) {
          
prevLine getLine(from.line 1);
          
prevLine.fixMarkEnds(lastLine);
        } else 
lastLine.fixMarkStarts();
        for (var 
0newText.length 1e; ++i)
          
added.push(Line.inheritMarks(newText[i], prevLine));
        if (
nlinesdoc.remove(from.linenlinescallbacks);
        if (
added.lengthdoc.insert(from.lineadded);
      } else if (
firstLine == lastLine) {
        if (
newText.length == 1)
          
firstLine.replace(from.chto.chnewText[0]);
        else {
          
lastLine firstLine.split(to.chnewText[newText.length-1]);
          
firstLine.replace(from.chnullnewText[0]);
          
firstLine.fixMarkEnds(lastLine);
          var 
added = [];
          for (var 
1newText.length 1e; ++i)
            
added.push(Line.inheritMarks(newText[i], firstLine));
          
added.push(lastLine);
          
doc.insert(from.line 1added);
        }
      } else if (
newText.length == 1) {
        
firstLine.replace(from.chnullnewText[0]);
        
lastLine.replace(nullto.ch"");
        
firstLine.append(lastLine);
        
doc.remove(from.line 1nlinescallbacks);
      } else {
        var 
added = [];
        
firstLine.replace(from.chnullnewText[0]);
        
lastLine.replace(nullto.chnewText[newText.length-1]);
        
firstLine.fixMarkEnds(lastLine);
        for (var 
1newText.length 1e; ++i)
          
added.push(Line.inheritMarks(newText[i], firstLine));
        if (
nlines 1doc.remove(from.line 1nlines 1callbacks);
        
doc.insert(from.line 1added);
      }
      if (
options.lineWrapping) {
        var 
perLine scroller.clientWidth charWidth() - 3;
        
doc.iter(from.linefrom.line newText.length, function(line) {
          if (
line.hidden) return;
          var 
guess Math.ceil(line.text.length perLine) || 1;
          if (
guess != line.heightupdateLineHeight(lineguess);
        });
      } else {
        
doc.iter(from.linenewText.length, function(line) {
          var 
line.text;
          if (
l.length maxLineLength) {
            
maxLine lmaxLineLength l.lengthmaxWidth null;
            
recomputeMaxLength false;
          }
        });
        if (
recomputeMaxLength) {
          
maxLineLength 0maxLine ""maxWidth null;
          
doc.iter(0doc.size, function(line) {
            var 
line.text;
            if (
l.length maxLineLength) {
              
maxLineLength l.lengthmaxLine l;
            }
          });
        }
      }

      
// Add these lines to the work array, so that they will be
      // highlighted. Adjust work lines if lines were added/removed.
      
var newWork = [], lendiff newText.length nlines 1;
      for (var 
0work.lengthl; ++i) {
        var 
task work[i];
        if (
task from.linenewWork.push(task);
        else if (
task to.linenewWork.push(task lendiff);
      }
      var 
hlEnd from.line Math.min(newText.length500);
      
highlightLines(from.linehlEnd);
      
newWork.push(hlEnd);
      
work newWork;
      
startWorker(100);
      
// Remember that these lines changed, for updating the display
      
changes.push({fromfrom.linetoto.line 1difflendiff});
      var 
changeObj = {fromfromtototextnewText};
      if (
textChanged) {
        for (var 
cur textChangedcur.nextcur cur.next) {}
        
cur.next changeObj;
      } else 
textChanged changeObj;

      
// Update the selection
      
function updateLine(n) {return <= Math.min(to.lineto.line lendiff) ? lendiff;}
      
setSelection(selFromselToupdateLine(sel.from.line), updateLine(sel.to.line));

      
// Make sure the scroll-size div has the correct height.
      
code.style.height = (doc.height textHeight() + paddingTop()) + "px";
    }

    function 
replaceRange(codefromto) {
      
from clipPos(from);
      if (!
toto from; else to clipPos(to);
      
code splitLines(code);
      function 
adjustPos(pos) {
        if (
posLess(posfrom)) return pos;
        if (!
posLess(topos)) return end;
        var 
line pos.line code.length - (to.line from.line) - 1;
        var 
ch pos.ch;
        if (
pos.line == to.line)
          
ch += code[code.length-1].length - (to.ch - (to.line == from.line from.ch 0));
        return {
linelinechch};
      }
      var 
end;
      
replaceRange1(codefromto, function(end1) {
        
end end1;
        return {
fromadjustPos(sel.from), toadjustPos(sel.to)};
      });
      return 
end;
    }
    function 
replaceSelection(codecollapse) {
      
replaceRange1(splitLines(code), sel.fromsel.to, function(end) {
        if (
collapse == "end") return {fromendtoend};
        else if (
collapse == "start") return {fromsel.fromtosel.from};
        else return {
fromsel.fromtoend};
      });
    }
    function 
replaceRange1(codefromtocomputeSel) {
      var 
endch code.length == code[0].length from.ch code[code.length-1].length;
      var 
newSel computeSel({linefrom.line code.length 1chendch});
      
updateLines(fromtocodenewSel.fromnewSel.to);
    }

    function 
getRange(fromto) {
      var 
l1 from.linel2 to.line;
      if (
l1 == l2) return getLine(l1).text.slice(from.chto.ch);
      var 
code = [getLine(l1).text.slice(from.ch)];
      
doc.iter(l1 1l2, function(line) { code.push(line.text); });
      
code.push(getLine(l2).text.slice(0to.ch));
      return 
code.join("n");
    }
    function 
getSelection() {
      return 
getRange(sel.fromsel.to);
    }

    var 
pollingFast false// Ensures slowPoll doesn't cancel fastPoll
    
function slowPoll() {
      if (
pollingFast) return;
      
poll.set(options.pollInterval, function() {
        
startOperation();
        
readInput();
        if (
focusedslowPoll();
        
endOperation();
      });
    }
    function 
fastPoll() {
      var 
missed false;
      
pollingFast true;
      function 
p() {
        
startOperation();
        var 
changed readInput();
        if (!
changed && !missed) {missed truepoll.set(60p);}
        else {
pollingFast falseslowPoll();}
        
endOperation();
      }
      
poll.set(20p);
    }

    
// Previnput is a hack to work with IME. If we reset the textarea
    // on every change, that breaks IME. So we look for changes
    // compared to the previous content instead. (Modern browsers have
    // events that indicate IME taking place, but these are not widely
    // supported or compatible enough yet to rely on.)
    
var prevInput "";
    function 
readInput() {
      if (
leaveInputAlone || !focused || hasSelection(input)) return false;
      var 
text input.value;
      if (
text == prevInput) return false;
      
shiftSelecting null;
      var 
same 0Math.min(prevInput.lengthtext.length);
      while (
same && prevInput[same] == text[same]) ++same;
      if (
same prevInput.length)
        
sel.from = {linesel.from.linechsel.from.ch - (prevInput.length same)};
      else if (
overwrite && posEq(sel.fromsel.to))
        
sel.to = {linesel.to.linechMath.min(getLine(sel.to.line).text.lengthsel.to.ch + (text.length same))};
      
replaceSelection(text.slice(same), "end");
      
prevInput text;
      return 
true;
    }
    function 
resetInput(user) {
      if (!
posEq(sel.fromsel.to)) {
        
prevInput "";
        
input.value getSelection();
        
input.select();
      } else if (
userprevInput input.value "";
    }

    function 
focusInput() {
      if (!
options.readOnlyinput.focus();
    }

    function 
scrollEditorIntoView() {
      if (!
cursor.getBoundingClientRect) return;
      var 
rect cursor.getBoundingClientRect();
      
// IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
      
if (ie && rect.top == rect.bottom) return;
      var 
winH window.innerHeight || Math.max(document.body.offsetHeightdocument.documentElement.offsetHeight);
      if (
rect.top || rect.bottom winHcursor.scrollIntoView();
    }
    function 
scrollCursorIntoView() {
      var 
cursor localCoords(sel.inverted sel.from sel.to);
      var 
options.lineWrapping Math.min(cursor.xlineSpace.offsetWidth) : cursor.x;
      return 
scrollIntoView(xcursor.yxcursor.yBot);
    }
    function 
scrollIntoView(x1y1x2y2) {
      var 
pl paddingLeft(), pt paddingTop(), lh textHeight();
      
y1 += pty2 += ptx1 += plx2 += pl;
      var 
screen scroller.clientHeightscreentop scroller.scrollTopscrolled falseresult true;
      if (
y1 screentop) {scroller.scrollTop Math.max(0y1 2*lh); scrolled true;}
      else if (
y2 screentop screen) {scroller.scrollTop y2 lh screenscrolled true;}

      var 
screenw scroller.clientWidthscreenleft scroller.scrollLeft;
      var 
gutterw options.fixedGutter gutter.clientWidth 0;
      if (
x1 screenleft gutterw) {
        if (
x1 50x1 0;
        
scroller.scrollLeft Math.max(0x1 10 gutterw);
        
scrolled true;
      }
      else if (
x2 screenw screenleft 3) {
        
scroller.scrollLeft x2 10 screenw;
        
scrolled true;
        if (
x2 code.clientWidthresult false;
      }
      if (
scrolled && options.onScrolloptions.onScroll(instance);
      return 
result;
    }

    function 
visibleLines() {
      var 
lh textHeight(), top scroller.scrollTop paddingTop();
      var 
from_height Math.max(0Math.floor(top lh));
      var 
to_height Math.ceil((top scroller.clientHeight) / lh);
      return {
fromlineAtHeight(docfrom_height),
              
tolineAtHeight(docto_height)};
    }
    
// Uses a set of changes plus the current scroll position to
    // determine which DOM updates have to be made, and makes the
    // updates.
    
function updateDisplay(changessuppressCallback) {
      if (!
scroller.clientWidth) {
        
showingFrom showingTo displayOffset 0;
        return;
      }
      
// Compute the new visible window
      
var visible visibleLines();
      
// Bail out if the visible area is already rendered and nothing changed.
      
if (changes !== true && changes.length == && visible.from >= showingFrom && visible.to <= showingTo) return;
      var 
from Math.max(visible.from 1000), to Math.min(doc.sizevisible.to 100);
      if (
showingFrom from && from showingFrom 20from showingFrom;
      if (
showingTo to && showingTo to 20to Math.min(doc.sizeshowingTo);

      
// Create a range of theoretically intact lines, and punch holes
      // in that using the change info.
      
var intact changes === true ? [] :
        
computeIntact([{fromshowingFromtoshowingTodomStart0}], changes);
      
// Clip off the parts that won't be visible
      
var intactLines 0;
      for (var 
0intact.length; ++i) {
        var 
range intact[i];
        if (
range.from from) {range.domStart += (from range.from); range.from from;}
        if (
range.to torange.to to;
        if (
range.from >= range.tointact.splice(i--, 1);
        else 
intactLines += range.to range.from;
      }
      if (
intactLines == to from) return;
      
intact.sort(function(ab) {return a.domStart b.domStart;});

      var 
th textHeight(), gutterDisplay gutter.style.display;
      
lineDiv.style.display gutter.style.display "none";
      
patchDisplay(fromtointact);
      
lineDiv.style.display "";

      
// Position the mover div to align with the lines it's supposed
      // to be showing (which will cover the visible display)
      
var different from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight th;
      
// This is just a bogus formula that detects when the editor is
      // resized or the font size changes.
      
if (differentlastSizeC scroller.clientHeight th;
      
showingFrom fromshowingTo to;
      
displayOffset heightAtLine(docfrom);
      
mover.style.top = (displayOffset th) + "px";
      
code.style.height = (doc.height th paddingTop()) + "px";

      
// Since this is all rather error prone, it is honoured with the
      // only assertion in the whole file.
      
if (lineDiv.childNodes.length != showingTo showingFrom)
        throw new 
Error("BAD PATCH! " JSON.stringify(intact) + " size=" + (showingTo showingFrom) +
                        
" nodes=" lineDiv.childNodes.length);

      if (
options.lineWrapping) {
        
maxWidth scroller.clientWidth;
        var 
curNode lineDiv.firstChild;
        
doc.iter(showingFromshowingTo, function(line) {
          if (!
line.hidden) {
            var 
height Math.round(curNode.offsetHeight th) || 1;
            if (
line.height != height) {updateLineHeight(lineheight); gutterDirty true;}
          }
          
curNode curNode.nextSibling;
        });
      } else {
        if (
maxWidth == nullmaxWidth stringWidth(maxLine);
        if (
maxWidth scroller.clientWidth) {
          
lineSpace.style.width maxWidth "px";
          
// Needed to prevent odd wrapping/hiding of widgets placed in here.
          
code.style.width "";
          
code.style.width scroller.scrollWidth "px";
        } else {
          
lineSpace.style.width code.style.width "";
        }
      }
      
gutter.style.display gutterDisplay;
      if (
different || gutterDirtyupdateGutter();
      
updateCursor();
      if (!
suppressCallback && options.onUpdateoptions.onUpdate(instance);
      return 
true;
    }

    function 
computeIntact(intactchanges) {
      for (var 
0changes.length || 0l; ++i) {
        var 
change changes[i], intact2 = [], diff change.diff || 0;
        for (var 
0l2 intact.lengthl2; ++j) {
          var 
range intact[j];
          if (
change.to <= range.from && change.diff)
            
intact2.push({fromrange.from difftorange.to diff,
                          
domStartrange.domStart});
          else if (
change.to <= range.from || change.from >= range.to)
            
intact2.push(range);
          else {
            if (
change.from range.from)
              
intact2.push({fromrange.fromtochange.fromdomStartrange.domStart});
            if (
change.to range.to)
              
intact2.push({fromchange.to difftorange.to diff,
                            
domStartrange.domStart + (change.to range.from)});
          }
        }
        
intact intact2;
      }
      return 
intact;
    }

    function 
patchDisplay(fromtointact) {
      
// The first pass removes the DOM nodes that aren't intact.
      
if (!intact.lengthlineDiv.innerHTML "";
      else {
        function 
killNode(node) {
          var 
tmp node.nextSibling;
          
node.parentNode.removeChild(node);
          return 
tmp;
        }
        var 
domPos 0curNode lineDiv.firstChildn;
        for (var 
0intact.length; ++i) {
          var 
cur intact[i];
          while (
cur.domStart domPos) {curNode killNode(curNode); domPos++;}
          for (var 
0cur.to cur.frome; ++j) {curNode curNode.nextSiblingdomPos++;}
        }
        while (
curNodecurNode killNode(curNode);
      }
      
// This pass fills in the lines that actually changed.
      
var nextIntact intact.shift(), curNode lineDiv.firstChildfrom;
      var 
sfrom sel.from.linesto sel.to.lineinSel sfrom from && sto >= from;
      var 
scratch targetDocument.createElement("div"), newElt;
      
doc.iter(fromto, function(line) {
        var 
ch1 nullch2 null;
        if (
inSel) {
          
ch1 0;
          if (
sto == j) {inSel falsech2 sel.to.ch;}
        } else if (
sfrom == j) {
          if (
sto == j) {ch1 sel.from.chch2 sel.to.ch;}
          else {
inSel truech1 sel.from.ch;}
        }
        if (
nextIntact && nextIntact.to == jnextIntact intact.shift();
        if (!
nextIntact || nextIntact.from j) {
          if (
line.hiddenscratch.innerHTML "<pre></pre>";
          else 
scratch.innerHTML line.getHTML(ch1ch2truetabText);
          
lineDiv.insertBefore(scratch.firstChildcurNode);
        } else {
          
curNode curNode.nextSibling;
        }
        ++
j;
      });
    }

    function 
updateGutter() {
      if (!
options.gutter && !options.lineNumbers) return;
      var 
hText mover.offsetHeighthEditor scroller.clientHeight;
      
gutter.style.height = (hText hEditor hEditor hText) + "px";
      var 
html = [], showingFrom;
      
doc.iter(showingFromMath.max(showingToshowingFrom 1), function(line) {
        if (
line.hidden) {
          
html.push("<pre></pre>");
        } else {
          var 
marker line.gutterMarker;
          var 
text options.lineNumbers options.firstLineNumber null;
          if (
marker && marker.text)
            
text marker.text.replace("%N%"text != null text "");
          else if (
text == null)
            
text "u00a0";
          
html.push((marker && marker.style '<pre class="' marker.style '">' "<pre>"), text);
          for (var 
1line.height; ++jhtml.push("<br/>&#160;");
          
html.push("</pre>");
        }
        ++
i;
      });
      
gutter.style.display "none";
      
gutterText.innerHTML html.join("");
      var 
minwidth String(doc.size).lengthfirstNode gutterText.firstChildval eltText(firstNode), pad "";
      while (
val.length pad.length minwidthpad += "u00a0";
      if (
padfirstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
      
gutter.style.display "";
      
lineSpace.style.marginLeft gutter.offsetWidth "px";
      
gutterDirty false;
    }
    function 
updateCursor() {
      var 
head sel.inverted sel.from sel.tolh textHeight();
      var 
pos localCoords(headtrue);
      var 
wrapOff eltOffset(wrapper), lineOff eltOffset(lineDiv);
      
inputDiv.style.top = (pos.lineOff.top wrapOff.top) + "px";
      
inputDiv.style.left = (pos.lineOff.left wrapOff.left) + "px";
      if (
posEq(sel.fromsel.to)) {
        
cursor.style.top pos."px";
        
cursor.style.left = (options.lineWrapping Math.min(pos.xlineSpace.offsetWidth) : pos.x) + "px";
        
cursor.style.display "";
      }
      else 
cursor.style.display "none";
    }

    function 
setShift(val) {
      if (
valshiftSelecting shiftSelecting || (sel.inverted sel.to sel.from);
      else 
shiftSelecting null;
    }
    function 
setSelectionUser(fromto) {
      var 
sh shiftSelecting && clipPos(shiftSelecting);
      if (
sh) {
        if (
posLess(shfrom)) from sh;
        else if (
posLess(tosh)) to sh;
      }
      
setSelection(fromto);
      
userSelChange true;
    }
    
// Update the selection. Last two args are only used by
    // updateLines, since they have to be expressed in the line
    // numbers before the update.
    
function setSelection(fromtooldFromoldTo) {
      
goalColumn null;
      if (
oldFrom == null) {oldFrom sel.from.lineoldTo sel.to.line;}
      if (
posEq(sel.fromfrom) && posEq(sel.toto)) return;
      if (
posLess(tofrom)) {var tmp toto fromfrom tmp;}

      
// Skip over hidden lines.
      
if (from.line != oldFromfrom skipHidden(fromoldFromsel.from.ch);
      if (
to.line != oldToto skipHidden(tooldTosel.to.ch);

      if (
posEq(fromto)) sel.inverted false;
      else if (
posEq(fromsel.to)) sel.inverted false;
      else if (
posEq(tosel.from)) sel.inverted true;

      
// Some ugly logic used to only mark the lines that actually did
      // see a change in selection as changed, rather than the whole
      // selected range.
      
if (posEq(fromto)) {
        if (!
posEq(sel.fromsel.to))
          
changes.push({fromoldFromtooldTo 1});
      }
      else if (
posEq(sel.fromsel.to)) {
        
changes.push({fromfrom.linetoto.line 1});
      }
      else {
        if (!
posEq(fromsel.from)) {
          if (
from.line oldFrom)
            
changes.push({fromfrom.linetoMath.min(to.lineoldFrom) + 1});
          else
            
changes.push({fromoldFromtoMath.min(oldTofrom.line) + 1});
        }
        if (!
posEq(tosel.to)) {
          if (
to.line oldTo)
            
changes.push({fromMath.max(oldFromfrom.line), tooldTo 1});
          else
            
changes.push({fromMath.max(from.lineoldTo), toto.line 1});
        }
      }
      
sel.from fromsel.to to;
      
selectionChanged true;
    }
    function 
skipHidden(posoldLineoldCh) {
      function 
getNonHidden(dir) {
        var 
lNo pos.line dirend dir == doc.size : -1;
        while (
lNo != end) {
          var 
line getLine(lNo);
          if (!
line.hidden) {
            var 
ch pos.ch;
            if (
ch oldCh || ch line.text.lengthch line.text.length;
            return {
linelNochch};
          }
          
lNo += dir;
        }
      }
      var 
line getLine(pos.line);
      if (!
line.hidden) return pos;
      if (
pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
      else return 
getNonHidden(-1) || getNonHidden(1);
    }
    function 
setCursor(linechuser) {
      var 
pos clipPos({linelinechch || 0});
      (
user setSelectionUser setSelection)(pospos);
    }

    function 
clipLine(n) {return Math.max(0Math.min(ndoc.size-1));}
    function 
clipPos(pos) {
      if (
pos.line 0) return {line0ch0};
      if (
pos.line >= doc.size) return {linedoc.size-1chgetLine(doc.size-1).text.length};
      var 
ch pos.chlinelen getLine(pos.line).text.length;
      if (
ch == null || ch linelen) return {linepos.linechlinelen};
      else if (
ch 0) return {linepos.linech0};
      else return 
pos;
    }

    function 
findPosH(dirunit) {
      var 
end sel.inverted sel.from sel.toline end.linech end.ch;
      var 
lineObj getLine(line);
      function 
findNextLine() {
        for (var 
line dirdir ? -doc.size!= e+= dir) {
          var 
lo getLine(l);
          if (!
lo.hidden) { line llineObj lo; return true; }
        }
      }
      function 
moveOnce(boundToLine) {
        if (
ch == (dir lineObj.text.length)) {
          if (!
boundToLine && findNextLine()) ch dir lineObj.text.length 0;
          else return 
false;
        } else 
ch += dir;
        return 
true;
      }
      if (
unit == "char"moveOnce();
      else if (
unit == "column"moveOnce(true);
      else if (
unit == "word") {
        var 
sawWord false;
        for (;;) {
          if (
dir 0) if (!moveOnce()) break;
          if (
isWordChar(lineObj.text.charAt(ch))) sawWord true;
          else if (
sawWord) {if (dir 0) {dir 1moveOnce();} break;}
          if (
dir 0) if (!moveOnce()) break;
        }
      }
      return {
linelinechch};
    }
    function 
moveH(dirunit) {
      var 
pos dir sel.from sel.to;
      if (
shiftSelecting || posEq(sel.fromsel.to)) pos findPosH(dirunit);
      
setCursor(pos.linepos.chtrue);
    }
    function 
deleteH(dirunit) {
      if (!
posEq(sel.fromsel.to)) replaceRange(""sel.fromsel.to);
      else if (
dir 0replaceRange(""findPosH(dirunit), sel.to);
      else 
replaceRange(""sel.fromfindPosH(dirunit));
      
userSelChange true;
    }
    var 
goalColumn null;
    function 
moveV(dirunit) {
      var 
dist 0pos localCoords(sel.inverted sel.from sel.totrue);
      if (
goalColumn != nullpos.goalColumn;
      if (
unit == "page"dist scroller.clientHeight;
      else if (
unit == "line"dist textHeight();
      var 
target coordsChar(pos.xpos.dist dir 2);
      
setCursor(target.linetarget.chtrue);
      
goalColumn pos.x;
    }

    function 
selectWordAt(pos) {
      var 
line getLine(pos.line).text;
      var 
start pos.chend pos.ch;
      while (
start && isWordChar(line.charAt(start 1))) --start;
      while (
end line.length && isWordChar(line.charAt(end))) ++end;
      
setSelectionUser({linepos.linechstart}, {linepos.linechend});
    }
    function 
selectLine(line) {
      
setSelectionUser({linelinech0}, {linelinechgetLine(line).text.length});
    }
    function 
indentSelected(mode) {
      if (
posEq(sel.fromsel.to)) return indentLine(sel.from.linemode);
      var 
sel.to.line - (sel.to.ch 1);
      for (var 
sel.from.line<= e; ++iindentLine(imode);
    }

    function 
indentLine(nhow) {
      if (!
howhow "add";
      if (
how == "smart") {
        if (!
mode.indenthow "prev";
        else var 
state getStateBefore(n);
      }

      var 
line getLine(n), curSpace line.indentation(options.tabSize),
          
curSpaceString line.text.match(/^s*/)[0], indentation;
      if (
how == "prev") {
        if (
nindentation getLine(n-1).indentation(options.tabSize);
        else 
indentation 0;
      }
      else if (
how == "smart"indentation mode.indent(stateline.text.slice(curSpaceString.length), line.text);
      else if (
how == "add"indentation curSpace options.indentUnit;
      else if (
how == "subtract"indentation curSpace options.indentUnit;
      
indentation Math.max(0indentation);
      var 
diff indentation curSpace;

      if (!
diff) {
        if (
sel.from.line != && sel.to.line != n) return;
        var 
indentString curSpaceString;
      }
      else {
        var 
indentString ""pos 0;
        if (
options.indentWithTabs)
          for (var 
Math.floor(indentation options.tabSize); i; --i) {pos += options.tabSizeindentString += "t";}
        while (
pos indentation) {++posindentString += " ";}
      }

      
replaceRange(indentString, {linench0}, {linenchcurSpaceString.length});
    }

    function 
loadMode() {
      
mode CodeMirror.getMode(optionsoptions.mode);
      
doc.iter(0doc.size, function(line) { line.stateAfter null; });
      
work = [0];
      
startWorker();
    }
    function 
gutterChanged() {
      var 
visible options.gutter || options.lineNumbers;
      
gutter.style.display visible "" "none";
      if (
visiblegutterDirty true;
      else 
lineDiv.parentNode.style.marginLeft 0;
    }
    function 
wrappingChanged(fromto) {
      if (
options.lineWrapping) {
        
wrapper.className += " CodeMirror-wrap";
        var 
perLine scroller.clientWidth charWidth() - 3;
        
doc.iter(0doc.size, function(line) {
          if (
line.hidden) return;
          var 
guess Math.ceil(line.text.length perLine) || 1;
          if (
guess != 1updateLineHeight(lineguess);
        });
        
lineSpace.style.width code.style.width "";
      } else {
        
wrapper.className wrapper.className.replace(" CodeMirror-wrap""");
        
maxWidth nullmaxLine "";
        
doc.iter(0doc.size, function(line) {
          if (
line.height != && !line.hiddenupdateLineHeight(line1);
          if (
line.text.length maxLine.lengthmaxLine line.text;
        });
      }
      
changes.push({from0todoc.size});
    }
    function 
computeTabText() {
      for (var 
str '<span class="cm-tab">'0options.tabSize; ++istr += " ";
      return 
str "</span>";
    }
    function 
tabsChanged() {
      
tabText computeTabText();
      
updateDisplay(true);
    }
    function 
themeChanged() {
      
scroller.className scroller.className.replace(/s*cm-s-w+/g"") +
        
options.theme.replace(/(^|s)s*/g" cm-s-");
    }

    function 
TextMarker() { this.set = []; }
    
TextMarker.prototype.clear operation(function() {
      var 
min Infinitymax = -Infinity;
      for (var 
0this.set.lengthe; ++i) {
        var 
line this.set[i], mk line.marked;
        if (!
mk || !line.parent) continue;
        var 
lineN lineNo(line);
        
min Math.min(minlineN); max Math.max(maxlineN);
        for (var 
0mk.length; ++j)
          if (
mk[j].set == this.setmk.splice(j--, 1);
      }
      if (
min != Infinity)
        
changes.push({frommintomax 1});
    });
    
TextMarker.prototype.find = function() {
      var 
fromto;
      for (var 
0this.set.lengthe; ++i) {
        var 
line this.set[i], mk line.marked;
        for (var 
0mk.length; ++j) {
          var 
mark mk[j];
          if (
mark.set == this.set) {
            if (
mark.from != null || mark.to != null) {
              var 
found lineNo(line);
              if (
found != null) {
                if (
mark.from != nullfrom = {linefoundchmark.from};
                if (
mark.to != nullto = {linefoundchmark.to};
              }
            }
          }
        }
      }
      return {
fromfromtoto};
    };

    function 
markText(fromtoclassName) {
      
from clipPos(from); to clipPos(to);
      var 
tm = new TextMarker();
      function 
add(linefromtoclassName) {
        
getLine(line).addMark(new MarkedText(fromtoclassNametm.set));
      }
      if (
from.line == to.lineadd(from.linefrom.chto.chclassName);
      else {
        
add(from.linefrom.chnullclassName);
        for (var 
from.line 1to.linee; ++i)
          
add(inullnullclassName);
        
add(to.linenullto.chclassName);
      }
      
changes.push({fromfrom.linetoto.line 1});
      return 
tm;
    }

    function 
setBookmark(pos) {
      
pos clipPos(pos);
      var 
bm = new Bookmark(pos.ch);
      
getLine(pos.line).addMark(bm);
      return 
bm;
    }

    function 
addGutterMarker(linetextclassName) {
      if (
typeof line == "number"line getLine(clipLine(line));
      
line.gutterMarker = {texttextstyleclassName};
      
gutterDirty true;
      return 
line;
    }
    function 
removeGutterMarker(line) {
      if (
typeof line == "number"line getLine(clipLine(line));
      
line.gutterMarker null;
      
gutterDirty true;
    }

    function 
changeLine(handleop) {
      var 
no handleline handle;
      if (
typeof handle == "number"line getLine(clipLine(handle));
      else 
no lineNo(handle);
      if (
no == null) return null;
      if (
op(lineno)) changes.push({fromnotono 1});
      else return 
null;
      return 
line;
    }
    function 
setLineClass(handleclassName) {
      return 
changeLine(handle, function(line) {
        if (
line.className != className) {
          
line.className className;
          return 
true;
        }
      });
    }
    function 
setLineHidden(handlehidden) {
      return 
changeLine(handle, function(lineno) {
        if (
line.hidden != hidden) {
          
line.hidden hidden;
          
updateLineHeight(linehidden 1);
          if (
hidden && (sel.from.line == no || sel.to.line == no))
            
setSelection(skipHidden(sel.fromsel.from.linesel.from.ch),
                         
skipHidden(sel.tosel.to.linesel.to.ch));
          return (
gutterDirty true);
        }
      });
    }

    function 
lineInfo(line) {
      if (
typeof line == "number") {
        if (!
isLine(line)) return null;
        var 
line;
        
line getLine(line);
        if (!
line) return null;
      }
      else {
        var 
lineNo(line);
        if (
== null) return null;
      }
      var 
marker line.gutterMarker;
      return {
linenhandlelinetextline.textmarkerTextmarker && marker.text,
              
markerClassmarker && marker.stylelineClassline.className};
    }

    function 
stringWidth(str) {
      
measure.innerHTML "<pre><span>x</span></pre>";
      
measure.firstChild.firstChild.firstChild.nodeValue str;
      return 
measure.firstChild.firstChild.offsetWidth || 10;
    }
    
// These are used to go from pixel positions to character
    // positions, taking varying character widths into account.
    
function charFromX(linex) {
      if (
<= 0) return 0;
      var 
lineObj getLine(line), text lineObj.text;
      function 
getX(len) {
        
measure.innerHTML "<pre><span>" lineObj.getHTML(nullnullfalsetabTextlen) + "</span></pre>";
        return 
measure.firstChild.firstChild.offsetWidth;
      }
      var 
from 0fromX 0to text.lengthtoX;
      
// Guess a suitable upper bound for our search.
      
var estimated Math.min(toMath.ceil(charWidth()));
      for (;;) {
        var 
estX getX(estimated);
        if (
estX <= && estimated toestimated Math.min(toMath.ceil(estimated 1.2));
        else {
toX estXto estimated; break;}
      }
      if (
toX) return to;
      
// Try to guess a suitable lower bound as well.
      
estimated Math.floor(to 0.8); estX getX(estimated);
      if (
estX x) {from estimatedfromX estX;}
      
// Do a binary search between these bounds.
      
for (;;) {
        if (
to from <= 1) return (toX fromX) ? from to;
        var 
middle Math.ceil((from to) / 2), middleX getX(middle);
        if (
middleX x) {to middletoX middleX;}
        else {
from middlefromX middleX;}
      }
    }

    var 
tempId Math.floor(Math.random() * 0xffffff).toString(16);
    function 
measureLine(linech) {
      var 
extra "";
      
// Include extra text at the end to make sure the measured line is wrapped in the right way.
      
if (options.lineWrapping) {
        var 
end line.text.indexOf(" "ch 2);
        
extra htmlEscape(line.text.slice(ch 1end line.text.length end + (ie 0)));
      }
      
measure.innerHTML "<pre>" line.getHTML(nullnullfalsetabTextch) +
        
'<span id="CodeMirror-temp-' tempId '">' htmlEscape(line.text.charAt(ch) || " ") + "</span>" +
        
extra "</pre>";
      var 
elt document.getElementById("CodeMirror-temp-" tempId);
      var 
top elt.offsetTopleft elt.offsetLeft;
      
// Older IEs report zero offsets for spans directly after a wrap
      
if (ie && ch && top == && left == 0) {
        var 
backup document.createElement("span");
        
backup.innerHTML "x";
        
elt.parentNode.insertBefore(backupelt.nextSibling);
        
top backup.offsetTop;
      }
      return {
toptopleftleft};
    }
    function 
localCoords(posinLineWrap) {
      var 
xlh textHeight(), lh * (heightAtLine(docpos.line) - (inLineWrap displayOffset 0));
      if (
pos.ch == 00;
      else {
        var 
sp measureLine(getLine(pos.line), pos.ch);
        
sp.left;
        if (
options.lineWrapping+= Math.max(0sp.top);
      }
      return {
xxyyyBotlh};
    }
    
// Coords must be lineSpace-local
    
function coordsChar(xy) {
      if (
00;
      var 
th textHeight(), cw charWidth(), heightPos displayOffset Math.floor(th);
      var 
lineNo lineAtHeight(docheightPos);
      if (
lineNo >= doc.size) return {linedoc.size 1chgetLine(doc.size 1).text.length};
      var 
lineObj getLine(lineNo), text lineObj.text;
      var 
tw options.lineWrappinginnerOff tw heightPos heightAtLine(doclineNo) : 0;
      if (
<= && innerOff == 0) return {linelineNoch0};
      function 
getX(len) {
        var 
sp measureLine(lineObjlen);
        if (
tw) {
          var 
off Math.round(sp.top th);
          return 
Math.max(0sp.left + (off innerOff) * scroller.clientWidth);
        }
        return 
sp.left;
      }
      var 
from 0fromX 0to text.lengthtoX;
      
// Guess a suitable upper bound for our search.
      
var estimated Math.min(toMath.ceil((innerOff scroller.clientWidth .9) / cw));
      for (;;) {
        var 
estX getX(estimated);
        if (
estX <= && estimated toestimated Math.min(toMath.ceil(estimated 1.2));
        else {
toX estXto estimated; break;}
      }
      if (
toX) return {linelineNochto};
      
// Try to guess a suitable lower bound as well.
      
estimated Math.floor(to 0.8); estX getX(estimated);
      if (
estX x) {from estimatedfromX estX;}
      
// Do a binary search between these bounds.
      
for (;;) {
        if (
to from <= 1) return {linelineNoch: (toX fromX) ? from to};
        var 
middle Math.ceil((from to) / 2), middleX getX(middle);
        if (
middleX x) {to middletoX middleX;}
        else {
from middlefromX middleX;}
      }
    }
    function 
pageCoords(pos) {
      var 
local localCoords(postrue), off eltOffset(lineSpace);
      return {
xoff.left local.xyoff.top local.yyBotoff.top local.yBot};
    }

    var 
cachedHeightcachedHeightFormeasureText;
    function 
textHeight() {
      if (
measureText == null) {
        
measureText "<pre>";
        for (var 
049; ++imeasureText += "x<br/>";
        
measureText += "x</pre>";
      }
      var 
offsetHeight lineDiv.clientHeight;
      if (
offsetHeight == cachedHeightFor) return cachedHeight;
      
cachedHeightFor offsetHeight;
      
measure.innerHTML measureText;
      
cachedHeight measure.firstChild.offsetHeight 50 || 1;
      
measure.innerHTML "";
      return 
cachedHeight;
    }
    var 
cachedWidthcachedWidthFor 0;
    function 
charWidth() {
      if (
scroller.clientWidth == cachedWidthFor) return cachedWidth;
      
cachedWidthFor scroller.clientWidth;
      return (
cachedWidth stringWidth("x"));
    }
    function 
paddingTop() {return lineSpace.offsetTop;}
    function 
paddingLeft() {return lineSpace.offsetLeft;}

    function 
posFromMouse(eliberal) {
      var 
offW eltOffset(scrollertrue), xy;
      
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
      
try { e.clientXe.clientY; } catch (e) { return null; }
      
// This is a mess of a heuristic to try and determine whether a
      // scroll-bar was clicked or not, and to return null if one was
      // (and !liberal).
      
if (!liberal && (offW.left scroller.clientWidth || offW.top scroller.clientHeight))
        return 
null;
      var 
offL eltOffset(lineSpacetrue);
      return 
coordsChar(offL.leftoffL.top);
    }
    function 
onContextMenu(e) {
      var 
pos posFromMouse(e);
      if (!
pos || window.opera) return; // Opera is difficult.
      
if (posEq(sel.fromsel.to) || posLess(possel.from) || !posLess(possel.to))
        
operation(setCursor)(pos.linepos.ch);

      var 
oldCSS input.style.cssText;
      
inputDiv.style.position "absolute";
      
input.style.cssText "position: fixed; width: 30px; height: 30px; top: " + (e.clientY 5) +
        
"px; left: " + (e.clientX 5) + "px; z-index: 1000; background: white; " +
        
"border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
      
leaveInputAlone true;
      var 
val input.value getSelection();
      
focusInput();
      
input.select();
      function 
rehide() {
        var 
newVal splitLines(input.value).join("n");
        if (
newVal != valoperation(replaceSelection)(newVal"end");
        
inputDiv.style.position "relative";
        
input.style.cssText oldCSS;
        
leaveInputAlone false;
        
resetInput(true);
        
slowPoll();
      }

      if (
gecko) {
        
e_stop(e);
        var 
mouseup connect(window"mouseup", function() {
          
mouseup();
          
setTimeout(rehide20);
        }, 
true);
      }
      else {
        
setTimeout(rehide50);
      }
    }

    
// Cursor-blinking
    
function restartBlink() {
      
clearInterval(blinker);
      var 
on true;
      
cursor.style.visibility "";
      
blinker setInterval(function() {
        
cursor.style.visibility = (on = !on) ? "" "hidden";
      }, 
650);
    }

    var 
matching = {"("")>"")""(<""[""]>""]""[<""{""}>""}""{<"};
    function 
matchBrackets(autoclear) {
      var 
head sel.inverted sel.from sel.toline getLine(head.line), pos head.ch 1;
      var 
match = (pos >= && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
      if (!
match) return;
      var 
ch match.charAt(0), forward match.charAt(1) == ">"forward : -1st line.styles;
      for (var 
off pos 10st.lengthei+=2)
        if ((
off -= st[i].length) <= 0) {var style st[i+1]; break;}

      var 
stack = [line.text.charAt(pos)], re = /[(){}[]]/;
      function 
scan(linefromto) {
        if (!
line.text) return;
        var 
st line.stylespos forward line.text.length 1cur;
        for (var 
forward st.length 2forward st.length : -2!= e+= 2*d) {
          var 
text st[i];
          if (
st[i+1] != null && st[i+1] != style) {pos += text.length; continue;}
          for (var 
forward text.length 1te forward text.length : -1!= te+= dpos+=d) {
            if (
pos >= from && pos to && re.test(cur text.charAt(j))) {
              var 
match matching[cur];
              if (
match.charAt(1) == ">" == forwardstack.push(cur);
              else if (
stack.pop() != match.charAt(0)) return {posposmatchfalse};
              else if (!
stack.length) return {posposmatchtrue};
            }
          }
        }
      }
      for (var 
head.lineforward Math.min(100doc.size) : Math.max(-1100); != ei+=d) {
        var 
line getLine(i), first == head.line;
        var 
found scan(linefirst && forward pos 0first && !forward pos line.text.length);
        if (
found) break;
      }
      if (!
foundfound = {posnullmatchfalse};
      var 
style found.match "CodeMirror-matchingbracket" "CodeMirror-nonmatchingbracket";
      var 
one markText({linehead.linechpos}, {linehead.linechpos+1}, style),
          
two found.pos != null && markText({lineichfound.pos}, {lineichfound.pos 1}, style);
      var 
clear operation(function(){one.clear(); two && two.clear();});
      if (
autoclearsetTimeout(clear800);
      else 
bracketHighlighted clear;
    }

    
// Finds the line to start with when starting a parse. Tries to
    // find a line with a stateAfter, so that it can start with a
    // valid state. If that fails, it returns the line with the
    // smallest indentation, which tends to need the least context to
    // parse correctly.
    
function findStartLine(n) {
      var 
minindentminline;
      for (var 
search nlim 40search lim; --search) {
        if (
search == 0) return 0;
        var 
line getLine(search-1);
        if (
line.stateAfter) return search;
        var 
indented line.indentation(options.tabSize);
        if (
minline == null || minindent indented) {
          
minline search 1;
          
minindent indented;
        }
      }
      return 
minline;
    }
    function 
getStateBefore(n) {
      var 
start findStartLine(n), state start && getLine(start-1).stateAfter;
      if (!
statestate startState(mode);
      else 
state copyState(modestate);
      
doc.iter(startn, function(line) {
        
line.highlight(modestateoptions.tabSize);
        
line.stateAfter copyState(modestate);
      });
      if (
start nchanges.push({fromstartton});
      if (
doc.size && !getLine(n).stateAfterwork.push(n);
      return 
state;
    }
    function 
highlightLines(startend) {
      var 
state getStateBefore(start);
      
doc.iter(startend, function(line) {
        
line.highlight(modestateoptions.tabSize);
        
line.stateAfter copyState(modestate);
      });
    }
    function 
highlightWorker() {
      var 
end = +new Date options.workTime;
      var 
foundWork work.length;
      while (
work.length) {
        if (!
getLine(showingFrom).stateAfter) var task showingFrom;
        else var 
task work.pop();
        if (
task >= doc.size) continue;
        var 
start findStartLine(task), state start && getLine(start-1).stateAfter;
        if (
statestate copyState(modestate);
        else 
state startState(mode);

        var 
unchanged 0compare mode.compareStatesrealChange false,
            
startbail false;
        
doc.iter(idoc.size, function(line) {
          var 
hadState line.stateAfter;
          if (+new 
Date end) {
            
work.push(i);
            
startWorker(options.workDelay);
            if (
realChangechanges.push({fromtaskto1});
            return (
bail true);
          }
          var 
changed line.highlight(modestateoptions.tabSize);
          if (
changedrealChange true;
          
line.stateAfter copyState(modestate);
          if (
compare) {
            if (
hadState && compare(hadStatestate)) return true;
          } else {
            if (
changed !== false || !hadStateunchanged 0;
            else if (++
unchanged && (!mode.indent || mode.indent(hadState"") == mode.indent(state"")))
              return 
true;
          }
          ++
i;
        });
        if (
bail) return;
        if (
realChangechanges.push({fromtaskto1});
      }
      if (
foundWork && options.onHighlightComplete)
        
options.onHighlightComplete(instance);
    }
    function 
startWorker(time) {
      if (!
work.length) return;
      
highlight.set(timeoperation(highlightWorker));
    }

    
// Operations are used to wrap changes in such a way that each
    // change won't have to update the cursor and display (which would
    // be awkward, slow, and error-prone), but instead updates are
    // batched and then all combined and executed at once.
    
function startOperation() {
      
updateInput userSelChange textChanged null;
      
changes = []; selectionChanged falsecallbacks = [];
    }
    function 
endOperation() {
      var 
reScroll falseupdated;
      if (
selectionChangedreScroll = !scrollCursorIntoView();
      if (
changes.lengthupdated updateDisplay(changestrue);
      else {
        if (
selectionChangedupdateCursor();
        if (
gutterDirtyupdateGutter();
      }
      if (
reScrollscrollCursorIntoView();
      if (
selectionChanged) {scrollEditorIntoView(); restartBlink();}

      if (
focused && !leaveInputAlone &&
          (
updateInput === true || (updateInput !== false && selectionChanged)))
        
resetInput(userSelChange);

      if (
selectionChanged && options.matchBrackets)
        
setTimeout(operation(function() {
          if (
bracketHighlighted) {bracketHighlighted(); bracketHighlighted null;}
          if (
posEq(sel.fromsel.to)) matchBrackets(false);
        }), 
20);
      var 
tc textChangedcbs callbacks// these can be reset by callbacks
      
if (selectionChanged && options.onCursorActivity)
        
options.onCursorActivity(instance);
      if (
tc && options.onChange && instance)
        
options.onChange(instancetc);
      for (var 
0cbs.length; ++icbs[i](instance);
      if (
updated && options.onUpdateoptions.onUpdate(instance);
    }
    var 
nestedOperation 0;
    function 
operation(f) {
      return function() {
        if (!
nestedOperation++) startOperation();
        try {var 
result f.apply(thisarguments);}
        finally {if (!--
nestedOperationendOperation();}
        return 
result;
      };
    }

    for (var 
ext in extensions)
      if (
extensions.propertyIsEnumerable(ext) &&
          !
instance.propertyIsEnumerable(ext))
        
instance[ext] = extensions[ext];
    return 
instance;
  } 
// (end of function CodeMirror)

  // The default configuration options.
  
CodeMirror.defaults = {
    
value"",
    
modenull,
    
theme"default",
    
indentUnit2,
    
indentWithTabsfalse,
    
tabSize4,
    
keyMap"default",
    
extraKeysnull,
    
electricCharstrue,
    
onKeyEventnull,
    
lineWrappingfalse,
    
lineNumbersfalse,
    
gutterfalse,
    
fixedGutterfalse,
    
firstLineNumber1,
    
readOnlyfalse,
    
onChangenull,
    
onCursorActivitynull,
    
onGutterClicknull,
    
onHighlightCompletenull,
    
onUpdatenull,
    
onFocusnullonBlurnullonScrollnull,
    
matchBracketsfalse,
    
workTime100,
    
workDelay200,
    
pollInterval100,
    
undoDepth40,
    
tabindexnull,
    
documentwindow.document
  
};

  var 
mac = /Mac/.test(navigator.platform);
  var 
win = /Win/.test(navigator.platform);

  
// Known modes, by name and by MIME
  
var modes = {}, mimeModes = {};
  
CodeMirror.defineMode = function(namemode) {
    if (!
CodeMirror.defaults.mode && name != "null"CodeMirror.defaults.mode name;
    
modes[name] = mode;
  };
  
CodeMirror.defineMIME = function(mimespec) {
    
mimeModes[mime] = spec;
  };
  
CodeMirror.getMode = function(optionsspec) {
    if (
typeof spec == "string" && mimeModes.hasOwnProperty(spec))
      
spec mimeModes[spec];
    if (
typeof spec == "string")
      var 
mname specconfig = {};
    else if (
spec != null)
      var 
mname spec.nameconfig spec;
    var 
mfactory modes[mname];
    if (!
mfactory) {
      if (
window.consoleconsole.warn("No mode " mname " found, falling back to plain text.");
      return 
CodeMirror.getMode(options"text/plain");
    }
    return 
mfactory(optionsconfig || {});
  };
  
CodeMirror.listModes = function() {
    var list = [];
    for (var 
m in modes)
      if (
modes.propertyIsEnumerable(m)) list.push(m);
    return list;
  };
  
CodeMirror.listMIMEs = function() {
    var list = [];
    for (var 
m in mimeModes)
      if (
mimeModes.propertyIsEnumerable(m)) list.push({mimemmodemimeModes[m]});
    return list;
  };

  var 
extensions CodeMirror.extensions = {};
  
CodeMirror.defineExtension = function(namefunc) {
    
extensions[name] = func;
  };

  var 
commands CodeMirror.commands = {
    
selectAll: function(cm) {cm.setSelection({line0ch0}, {linecm.lineCount() - 1});},
    
killLine: function(cm) {
      var 
from cm.getCursor(true), to cm.getCursor(false), sel = !posEq(fromto);
      if (!
sel && cm.getLine(from.line).length == from.chcm.replaceRange(""from, {linefrom.line 1ch0});
      else 
cm.replaceRange(""fromsel to : {linefrom.line});
    },
    
deleteLine: function(cm) {var cm.getCursor().linecm.replaceRange("", {linelch0}, {linel});},
    
undo: function(cm) {cm.undo();},
    
redo: function(cm) {cm.redo();},
    
goDocStart: function(cm) {cm.setCursor(00true);},
    
goDocEnd: function(cm) {cm.setSelection({linecm.lineCount() - 1}, nulltrue);},
    
goLineStart: function(cm) {cm.setCursor(cm.getCursor().line0true);},
    
goLineStartSmart: function(cm) {
      var 
cur cm.getCursor();
      var 
text cm.getLine(cur.line), firstNonWS Math.max(0text.search(/S/));
      
cm.setCursor(cur.linecur.ch <= firstNonWS && cur.ch firstNonWStrue);
    },
    
goLineEnd: function(cm) {cm.setSelection({linecm.getCursor().line}, nulltrue);},
    
goLineUp: function(cm) {cm.moveV(-1"line");},
    
goLineDown: function(cm) {cm.moveV(1"line");},
    
goPageUp: function(cm) {cm.moveV(-1"page");},
    
goPageDown: function(cm) {cm.moveV(1"page");},
    
goCharLeft: function(cm) {cm.moveH(-1"char");},
    
goCharRight: function(cm) {cm.moveH(1"char");},
    
goColumnLeft: function(cm) {cm.moveH(-1"column");},
    
goColumnRight: function(cm) {cm.moveH(1"column");},
    
goWordLeft: function(cm) {cm.moveH(-1"word");},
    
goWordRight: function(cm) {cm.moveH(1"word");},
    
delCharLeft: function(cm) {cm.deleteH(-1"char");},
    
delCharRight: function(cm) {cm.deleteH(1"char");},
    
delWordLeft: function(cm) {cm.deleteH(-1"word");},
    
delWordRight: function(cm) {cm.deleteH(1"word");},
    
indentAuto: function(cm) {cm.indentSelection("smart");},
    
indentMore: function(cm) {cm.indentSelection("add");},
    
indentLess: function(cm) {cm.indentSelection("subtract");},
    
insertTab: function(cm) {cm.replaceSelection("t""end");},
    
transposeChars: function(cm) {
      var 
cur cm.getCursor(), line cm.getLine(cur.line);
      if (
cur.ch && cur.ch line.length 1)
        
cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch 1),
                        {
linecur.linechcur.ch 1}, {linecur.linechcur.ch 1});
    },
    
newlineAndIndent: function(cm) {
      
cm.replaceSelection("n""end");
      
cm.indentLine(cm.getCursor().line);
    },
    
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
  };

  var 
keyMap CodeMirror.keyMap = {};
  
keyMap.basic = {
    
"Left""goCharLeft""Right""goCharRight""Up""goLineUp""Down""goLineDown",
    
"End""goLineEnd""Home""goLineStartSmart""PageUp""goPageUp""PageDown""goPageDown",
    
"Delete""delCharRight""Backspace""delCharLeft""Tab""indentMore""Shift-Tab""indentLess",
    
"Enter""newlineAndIndent""Insert""toggleOverwrite"
  
};
  
// Note that the save and find-related commands aren't defined by
  // default. Unknown commands are simply ignored.
  
keyMap.pcDefault = {
    
"Ctrl-A""selectAll""Ctrl-D""deleteLine""Ctrl-Z""undo""Shift-Ctrl-Z""redo""Ctrl-Y""redo",
    
"Ctrl-Home""goDocStart""Alt-Up""goDocStart""Ctrl-End""goDocEnd""Ctrl-Down""goDocEnd",
    
"Ctrl-Left""goWordLeft""Ctrl-Right""goWordRight""Alt-Left""goLineStart""Alt-Right""goLineEnd",
    
"Ctrl-Backspace""delWordLeft""Ctrl-Delete""delWordRight""Ctrl-S""save""Ctrl-F""find",
    
"Ctrl-G""findNext""Shift-Ctrl-G""findPrev""Shift-Ctrl-F""replace""Shift-Ctrl-R""replaceAll",
    
fallthrough"basic"
  
};
  
keyMap.macDefault = {
    
"Cmd-A""selectAll""Cmd-D""deleteLine""Cmd-Z""undo""Shift-Cmd-Z""redo""Cmd-Y""redo",
    
"Cmd-Up""goDocStart""Cmd-End""goDocEnd""Cmd-Down""goDocEnd""Alt-Left""goWordLeft",
    
"Alt-Right""goWordRight""Cmd-Left""goLineStart""Cmd-Right""goLineEnd""Alt-Backspace""delWordLeft",
    
"Ctrl-Alt-Backspace""delWordRight""Alt-Delete""delWordRight""Cmd-S""save""Cmd-F""find",
    
"Cmd-G""findNext""Shift-Cmd-G""findPrev""Cmd-Alt-F""replace""Shift-Cmd-Alt-F""replaceAll",
    
fallthrough: ["basic""emacsy"]
  };
  
keyMap["default"] = mac keyMap.macDefault keyMap.pcDefault;
  
keyMap.emacsy = {
    
"Ctrl-F""goCharRight""Ctrl-B""goCharLeft""Ctrl-P""goLineUp""Ctrl-N""goLineDown",
    
"Alt-F""goWordRight""Alt-B""goWordLeft""Ctrl-A""goLineStart""Ctrl-E""goLineEnd",
    
"Ctrl-V""goPageUp""Shift-Ctrl-V""goPageDown""Ctrl-D""delCharRight""Ctrl-H""delCharLeft",
    
"Alt-D""delWordRight""Alt-Backspace""delWordLeft""Ctrl-K""killLine""Ctrl-T""transposeChars"
  
};

  function 
lookupKey(nameextraMapmap) {
    function 
lookup(namemapft) {
      var 
found map[name];
      if (
found != null) return found;
      if (
ft == nullft map.fallthrough;
      if (
ft == null) return map.catchall;
      if (
typeof ft == "string") return lookup(namekeyMap[ft]);
      for (var 
0ft.lengthe; ++i) {
        
found lookup(namekeyMap[ft[i]]);
        if (
found != null) return found;
      }
      return 
null;
    }
    return 
extraMap lookup(nameextraMapmap) : lookup(namekeyMap[map]);
  }
  function 
isModifierKey(event) {
    var 
name keyNames[event.keyCode];
    return 
name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
  }

  
CodeMirror.fromTextArea = function(textareaoptions) {
    if (!
optionsoptions = {};
    
options.value textarea.value;
    if (!
options.tabindex && textarea.tabindex)
      
options.tabindex textarea.tabindex;

    function 
save() {textarea.value instance.getValue();}
    if (
textarea.form) {
      
// Deplorable hack to make the submit method do the right thing.
      
var rmSubmit connect(textarea.form"submit"savetrue);
      if (
typeof textarea.form.submit == "function") {
        var 
realSubmit textarea.form.submit;
        function 
wrappedSubmit() {
          
save();
          
textarea.form.submit realSubmit;
          
textarea.form.submit();
          
textarea.form.submit wrappedSubmit;
        }
        
textarea.form.submit wrappedSubmit;
      }
    }

    
textarea.style.display "none";
    var 
instance CodeMirror(function(node) {
      
textarea.parentNode.insertBefore(nodetextarea.nextSibling);
    }, 
options);
    
instance.save save;
    
instance.getTextArea = function() { return textarea; };
    
instance.toTextArea = function() {
      
save();
      
textarea.parentNode.removeChild(instance.getWrapperElement());
      
textarea.style.display "";
      if (
textarea.form) {
        
rmSubmit();
        if (
typeof textarea.form.submit == "function")
          
textarea.form.submit realSubmit;
      }
    };
    return 
instance;
  };

  
// Utility functions for working with state. Exported because modes
  // sometimes need to do this.
  
function copyState(modestate) {
    if (
state === true) return state;
    if (
mode.copyState) return mode.copyState(state);
    var 
nstate = {};
    for (var 
n in state) {
      var 
val state[n];
      if (
val instanceof Array) val val.concat([]);
      
nstate[n] = val;
    }
    return 
nstate;
  }
  
CodeMirror.copyState copyState;
  function 
startState(modea1a2) {
    return 
mode.startState mode.startState(a1a2) : true;
  }
  
CodeMirror.startState startState;

  
// The character stream used by a mode's parser.
  
function StringStream(stringtabSize) {
    
this.pos this.start 0;
    
this.string string;
    
this.tabSize tabSize || 8;
  }
  
StringStream.prototype = {
    
eol: function() {return this.pos >= this.string.length;},
    
sol: function() {return this.pos == 0;},
    
peek: function() {return this.string.charAt(this.pos);},
    
next: function() {
      if (
this.pos this.string.length)
        return 
this.string.charAt(this.pos++);
    },
    
eat: function(match) {
      var 
ch this.string.charAt(this.pos);
      if (
typeof match == "string") var ok ch == match;
      else var 
ok ch && (match.test match.test(ch) : match(ch));
      if (
ok) {++this.pos; return ch;}
    },
    
eatWhile: function(match) {
      var 
start this.pos;
      while (
this.eat(match)){}
      return 
this.pos start;
    },
    
eatSpace: function() {
      var 
start this.pos;
      while (/[
su00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
      return 
this.pos start;
    },
    
skipToEnd: function() {this.pos this.string.length;},
    
skipTo: function(ch) {
      var 
found this.string.indexOf(chthis.pos);
      if (
found > -1) {this.pos found; return true;}
    },
    
backUp: function(n) {this.pos -= n;},
    
column: function() {return countColumn(this.stringthis.startthis.tabSize);},
    
indentation: function() {return countColumn(this.stringnullthis.tabSize);},
    
match: function(patternconsumecaseInsensitive) {
      if (
typeof pattern == "string") {
        function 
cased(str) {return caseInsensitive str.toLowerCase() : str;}
        if (
cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
          if (
consume !== falsethis.pos += pattern.length;
          return 
true;
        }
      }
      else {
        var 
match this.string.slice(this.pos).match(pattern);
        if (
match && consume !== falsethis.pos += match[0].length;
        return 
match;
      }
    },
    
current: function(){return this.string.slice(this.startthis.pos);}
  };
  
CodeMirror.StringStream StringStream;

  function 
MarkedText(fromtoclassNameset) {
    
this.from fromthis.to tothis.style classNamethis.set set;
  }
  
MarkedText.prototype = {
    
attach: function(line) { this.set.push(line); },
    
detach: function(line) {
      var 
ix indexOf(this.setline);
      if (
ix > -1this.set.splice(ix1);
    },
    
split: function(poslenBefore) {
      if (
this.to <= pos && this.to != null) return null;
      var 
from this.from pos || this.from == null null this.from pos lenBefore;
      var 
to this.to == null null this.to pos lenBefore;
      return new 
MarkedText(fromtothis.stylethis.set);
    },
    
dup: function() { return new MarkedText(nullnullthis.stylethis.set); },
    
clipTo: function(fromOpenfromtoOpentodiff) {
      if (
this.from != null && this.from >= from)
        
this.from Math.max(tothis.from) + diff;
      if (
this.to != null && this.to from)
        
this.to to this.to this.to diff from;
      if (
fromOpen && to this.from && (to this.to || this.to == null))
        
this.from null;
      if (
toOpen && (from this.to || this.to == null) && (from this.from || this.from == null))
        
this.to null;
    },
    
isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
    
sameSet: function(x) { return this.set == x.set; }
  };

  function 
Bookmark(pos) {
    
this.from posthis.to posthis.line null;
  }
  
Bookmark.prototype = {
    
attach: function(line) { this.line line; },
    
detach: function(line) { if (this.line == linethis.line null; },
    
split: function(poslenBefore) {
      if (
pos this.from) {
        
this.from this.to = (this.from pos) + lenBefore;
        return 
this;
      }
    },
    
isDead: function() { return this.from this.to; },
    
clipTo: function(fromOpenfromtoOpentodiff) {
      if ((
fromOpen || from this.from) && (toOpen || to this.to)) {
        
this.from 0this.to = -1;
      } else if (
this.from from) {
        
this.from this.to Math.max(tothis.from) + diff;
      }
    },
    
sameSet: function(x) { return false; },
    
find: function() {
      if (!
this.line || !this.line.parent) return null;
      return {
linelineNo(this.line), chthis.from};
    },
    
clear: function() {
      if (
this.line) {
        var 
found indexOf(this.line.markedthis);
        if (
found != -1this.line.marked.splice(found1);
        
this.line null;
      }
    }
  };

  
// Line objects. These hold state related to a line, including
  // highlighting info (the styles array).
  
function Line(textstyles) {
    
this.styles styles || [textnull];
    
this.text text;
    
this.height 1;
    
this.marked this.gutterMarker this.className this.handlers null;
    
this.stateAfter this.parent this.hidden null;
  }
  
Line.inheritMarks = function(textorig) {
    var 
ln = new Line(text), mk orig && orig.marked;
    if (
mk) {
      for (var 
0mk.length; ++i) {
        if (
mk[i].to == null && mk[i].style) {
          var 
newmk ln.marked || (ln.marked = []), mark mk[i];
          var 
nmark mark.dup(); newmk.push(nmark); nmark.attach(ln);
        }
      }
    }
    return 
ln;
  }
  
Line.prototype = {
    
// Replace a piece of a line, keeping the styles around it intact.
    
replace: function(fromto_text) {
      var 
st = [], mk this.markedto to_ == null this.text.length to_;
      
copyStyles(0fromthis.stylesst);
      if (
textst.push(textnull);
      
copyStyles(tothis.text.lengththis.stylesst);
      
this.styles st;
      
this.text this.text.slice(0from) + text this.text.slice(to);
      
this.stateAfter null;
      if (
mk) {
        var 
diff text.length - (to from);
        for (var 
0mark mk[i]; mk.length; ++i) {
          
mark.clipTo(from == nullfrom || 0to_ == nulltodiff);
          if (
mark.isDead()) {mark.detach(this); mk.splice(i--, 1);}
        }
      }
    },
    
// Split a part off a line, keeping styles and markers intact.
    
split: function(postextBefore) {
      var 
st = [textBeforenull], mk this.marked;
      
copyStyles(posthis.text.lengththis.stylesst);
      var 
taken = new Line(textBefore this.text.slice(pos), st);
      if (
mk) {
        for (var 
0mk.length; ++i) {
          var 
mark mk[i];
          var 
newmark mark.split(postextBefore.length);
          if (
newmark) {
            if (!
taken.markedtaken.marked = [];
            
taken.marked.push(newmark); newmark.attach(taken);
          }
        }
      }
      return 
taken;
    },
    
append: function(line) {
      var 
mylen this.text.lengthmk line.markedmymk this.marked;
      
this.text += line.text;
      
copyStyles(0line.text.lengthline.stylesthis.styles);
      if (
mymk) {
        for (var 
0mymk.length; ++i)
          if (
mymk[i].to == nullmymk[i].to mylen;
      }
      if (
mk && mk.length) {
        if (!
mymkthis.marked mymk = [];
        
outer: for (var 0mk.length; ++i) {
          var 
mark mk[i];
          if (!
mark.from) {
            for (var 
0mymk.length; ++j) {
              var 
mymark mymk[j];
              if (
mymark.to == mylen && mymark.sameSet(mark)) {
                
mymark.to mark.to == null null mark.to mylen;
                if (
mymark.isDead()) {
                  
mymark.detach(this);
                  
mk.splice(i--, 1);
                }
                continue 
outer;
              }
            }
          }
          
mymk.push(mark);
          
mark.attach(this);
          
mark.from += mylen;
          if (
mark.to != nullmark.to += mylen;
        }
      }
    },
    
fixMarkEnds: function(other) {
      var 
mk this.markedomk other.marked;
      if (!
mk) return;
      for (var 
0mk.length; ++i) {
        var 
mark mk[i], close mark.to == null;
        if (
close && omk) {
          for (var 
0omk.length; ++j)
            if (
omk[j].sameSet(mark)) {close false; break;}
        }
        if (
closemark.to this.text.length;
      }
    },
    
fixMarkStarts: function() {
      var 
mk this.marked;
      if (!
mk) return;
      for (var 
0mk.length; ++i)
        if (
mk[i].from == nullmk[i].from 0;
    },
    
addMark: function(mark) {
      
mark.attach(this);
      if (
this.marked == nullthis.marked = [];
      
this.marked.push(mark);
      
this.marked.sort(function(ab){return (a.from || 0) - (b.from || 0);});
    },
    
// Run the given mode's parser over a line, update the styles
    // array, which contains alternating fragments of text and CSS
    // classes.
    
highlight: function(modestatetabSize) {
      var 
stream = new StringStream(this.texttabSize), st this.stylespos 0;
      var 
changed falsecurWord st[0], prevWord;
      if (
this.text == "" && mode.blankLinemode.blankLine(state);
      while (!
stream.eol()) {
        var 
style mode.token(streamstate);
        var 
substr this.text.slice(stream.startstream.pos);
        
stream.start stream.pos;
        if (
pos && st[pos-1] == style)
          
st[pos-2] += substr;
        else if (
substr) {
          if (!
changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed true;
          
st[pos++] = substrst[pos++] = style;
          
prevWord curWordcurWord st[pos];
        }
        
// Give up when line is ridiculously long
        
if (stream.pos 5000) {
          
st[pos++] = this.text.slice(stream.pos); st[pos++] = null;
          break;
        }
      }
      if (
st.length != pos) {st.length poschanged true;}
      if (
pos && st[pos-2] != prevWordchanged true;
      
// Short lines with simple highlights return null, and are
      // counted as changed by the driver because they are likely to
      // highlight the same way in various contexts.
      
return changed || (st.length && this.text.length 10 null false);
    },
    
// Fetch the parser token for a given character. Useful for hacks
    // that want to inspect the mode state (say, for completion).
    
getTokenAt: function(modestatech) {
      var 
txt this.textstream = new StringStream(txt);
      while (
stream.pos ch && !stream.eol()) {
        
stream.start stream.pos;
        var 
style mode.token(streamstate);
      }
      return {
startstream.start,
              
endstream.pos,
              
stringstream.current(),
              
classNamestyle || null,
              
statestate};
    },
    
indentation: function(tabSize) {return countColumn(this.textnulltabSize);},
    
// Produces an HTML fragment for the line, taking selection,
    // marking, and highlighting into account.
    
getHTML: function(sfromstoincludePretabTextendAt) {
      var 
html = [], first true;
      if (
includePre)
        
html.push(this.className '<pre class="' this.className '">'"<pre>");
      function 
span(textstyle) {
        if (!
text) return;
        
// Work around a bug where, in some compat modes, IE ignores leading spaces
        
if (first && ie && text.charAt(0) == " "text "u00a0" text.slice(1);
        
first false;
        if (
stylehtml.push('<span class="'style'">'htmlEscape(text).replace(/t/gtabText), "</span>");
        else 
html.push(htmlEscape(text).replace(/t/gtabText));
      }
      var 
st this.stylesallText this.textmarked this.marked;
      if (
sfrom == stosfrom null;
      var 
len allText.length;
      if (
endAt != nulllen Math.min(endAtlen);

      if (!
allText && endAt == null)
        
span(" "sfrom != null && sto == null "CodeMirror-selected" null);
      else if (!
marked && sfrom == null)
        for (var 
0ch 0ch leni+=2) {
          var 
str st[i], style st[i+1], str.length;
          if (
ch lenstr str.slice(0len ch);
          
ch += l;
          
span(strstyle && "cm-" style);
        }
      else {
        var 
pos 00text ""stylesg 0;
        var 
markpos = -1mark null;
        function 
nextMark() {
          if (
marked) {
            
markpos += 1;
            
mark = (markpos marked.length) ? marked[markpos] : null;
          }
        }
        
nextMark();
        while (
pos len) {
          var 
upto len;
          var 
extraStyle "";
          if (
sfrom != null) {
            if (
sfrom posupto sfrom;
            else if (
sto == null || sto pos) {
              
extraStyle " CodeMirror-selected";
              if (
sto != nullupto Math.min(uptosto);
            }
          }
          while (
mark && mark.to != null && mark.to <= posnextMark();
          if (
mark) {
            if (
mark.from posupto Math.min(uptomark.from);
            else {
              
extraStyle += " " mark.style;
              if (
mark.to != nullupto Math.min(uptomark.to);
            }
          }
          for (;;) {
            var 
end pos text.length;
            var 
appliedStyle style;
            if (
extraStyleappliedStyle style style extraStyle extraStyle;
            
span(end upto text.slice(0upto pos) : textappliedStyle);
            if (
end >= upto) {text text.slice(upto pos); pos upto; break;}
            
pos end;
            
text st[i++]; style "cm-" st[i++];
          }
        }
        if (
sfrom != null && sto == nullspan(" ""CodeMirror-selected");
      }
      if (
includePrehtml.push("</pre>");
      return 
html.join("");
    },
    
cleanUp: function() {
      
this.parent null;
      if (
this.marked)
        for (var 
0this.marked.lengthe; ++ithis.marked[i].detach(this);
    }
  };
  
// Utility used by replace and split above
  
function copyStyles(fromtosourcedest) {
    for (var 
0pos 0state 0pos toi+=2) {
      var 
part source[i], end pos part.length;
      if (
state == 0) {
        if (
end fromdest.push(part.slice(from posMath.min(part.lengthto pos)), source[i+1]);
        if (
end >= fromstate 1;
      }
      else if (
state == 1) {
        if (
end todest.push(part.slice(0to pos), source[i+1]);
        else 
dest.push(partsource[i+1]);
      }
      
pos end;
    }
  }

  
// Data structure that holds the sequence of lines.
  
function LeafChunk(lines) {
    
this.lines lines;
    
this.parent null;
    for (var 
0lines.lengthheight 0e; ++i) {
      
lines[i].parent this;
      
height += lines[i].height;
    }
    
this.height height;
  }
  
LeafChunk.prototype = {
    
chunkSize: function() { return this.lines.length; },
    
remove: function(atncallbacks) {
      for (var 
atat ne; ++i) {
        var 
line this.lines[i];
        
this.height -= line.height;
        
line.cleanUp();
        if (
line.handlers)
          for (var 
0line.handlers.length; ++jcallbacks.push(line.handlers[j]);
      }
      
this.lines.splice(atn);
    },
    
collapse: function(lines) {
      
lines.splice.apply(lines, [lines.length0].concat(this.lines));
    },
    
insertHeight: function(atlinesheight) {
      
this.height += height;
      
this.lines.splice.apply(this.lines, [at0].concat(lines));
      for (var 
0lines.lengthe; ++ilines[i].parent this;
    },
    
iterN: function(atnop) {
      for (var 
at nat e; ++at)
        if (
op(this.lines[at])) return true;
    }
  };
  function 
BranchChunk(children) {
    
this.children children;
    var 
size 0height 0;
    for (var 
0children.lengthe; ++i) {
      var 
ch children[i];
      
size += ch.chunkSize(); height += ch.height;
      
ch.parent this;
    }
    
this.size size;
    
this.height height;
    
this.parent null;
  }
  
BranchChunk.prototype = {
    
chunkSize: function() { return this.size; },
    
remove: function(atncallbacks) {
      
this.size -= n;
      for (var 
0this.children.length; ++i) {
        var 
child this.children[i], sz child.chunkSize();
        if (
at sz) {
          var 
rm Math.min(nsz at), oldHeight child.height;
          
child.remove(atrmcallbacks);
          
this.height -= oldHeight child.height;
          if (
sz == rm) { this.children.splice(i--, 1); child.parent null; }
          if ((
-= rm) == 0) break;
          
at 0;
        } else 
at -= sz;
      }
      if (
this.size 25) {
        var 
lines = [];
        
this.collapse(lines);
        
this.children = [new LeafChunk(lines)];
      }
    },
    
collapse: function(lines) {
      for (var 
0this.children.lengthe; ++ithis.children[i].collapse(lines);
    },
    
insert: function(atlines) {
      var 
height 0;
      for (var 
0lines.lengthe; ++iheight += lines[i].height;
      
this.insertHeight(atlinesheight);
    },
    
insertHeight: function(atlinesheight) {
      
this.size += lines.length;
      
this.height += height;
      for (var 
0this.children.lengthe; ++i) {
        var 
child this.children[i], sz child.chunkSize();
        if (
at <= sz) {
          
child.insertHeight(atlinesheight);
          if (
child.lines && child.lines.length 50) {
            while (
child.lines.length 50) {
              var 
spilled child.lines.splice(child.lines.length 2525);
              var 
newleaf = new LeafChunk(spilled);
              
child.height -= newleaf.height;
              
this.children.splice(10newleaf);
              
newleaf.parent this;
            }
            
this.maybeSpill();
          }
          break;
        }
        
at -= sz;
      }
    },
    
maybeSpill: function() {
      if (
this.children.length <= 10) return;
      var 
me this;
      do {
        var 
spilled me.children.splice(me.children.length 55);
        var 
sibling = new BranchChunk(spilled);
        if (!
me.parent) { // Become the parent node
          
var copy = new BranchChunk(me.children);
          
copy.parent me;
          
me.children = [copysibling];
          
me copy;
        } else {
          
me.size -= sibling.size;
          
me.height -= sibling.height;
          var 
myIndex indexOf(me.parent.childrenme);
          
me.parent.children.splice(myIndex 10sibling);
        }
        
sibling.parent me.parent;
      } while (
me.children.length 10);
      
me.parent.maybeSpill();
    },
    
iter: function(fromtoop) { this.iterN(fromto fromop); },
    
iterN: function(atnop) {
      for (var 
0this.children.lengthe; ++i) {
        var 
child this.children[i], sz child.chunkSize();
        if (
at sz) {
          var 
used Math.min(nsz at);
          if (
child.iterN(atusedop)) return true;
          if ((
-= used) == 0) break;
          
at 0;
        } else 
at -= sz;
      }
    }
  };

  function 
getLineAt(chunkn) {
    while (!
chunk.lines) {
      for (var 
0;; ++i) {
        var 
child chunk.children[i], sz child.chunkSize();
        if (
sz) { chunk child; break; }
        
-= sz;
      }
    }
    return 
chunk.lines[n];
  }
  function 
lineNo(line) {
    if (
line.parent == null) return null;
    var 
cur line.parentno indexOf(cur.linesline);
    for (var 
chunk cur.parentchunkcur chunkchunk chunk.parent) {
      for (var 
0chunk.children.length; ; ++i) {
        if (
chunk.children[i] == cur) break;
        
no += chunk.children[i].chunkSize();
      }
    }
    return 
no;
  }
  function 
lineAtHeight(chunkh) {
    var 
0;
    
outer: do {
      for (var 
0chunk.children.lengthe; ++i) {
        var 
child chunk.children[i], ch child.height;
        if (
ch) { chunk child; continue outer; }
        
-= ch;
        
+= child.chunkSize();
      }
      return 
n;
    } while (!
chunk.lines);
    for (var 
0chunk.lines.lengthe; ++i) {
      var 
line chunk.lines[i], lh line.height;
      if (
lh) break;
      
-= lh;
    }
    return 
i;
  }
  function 
heightAtLine(chunkn) {
    var 
0;
    
outer: do {
      for (var 
0chunk.children.lengthe; ++i) {
        var 
child chunk.children[i], sz child.chunkSize();
        if (
sz) { chunk child; continue outer; }
        
-= sz;
        
+= child.height;
      }
      return 
h;
    } while (!
chunk.lines);
    for (var 
0n; ++i+= chunk.lines[i].height;
    return 
h;
  }

  
// The history object 'chunks' changes that are made close together
  // and at almost the same time into bigger undoable units.
  
function History() {
    
this.time 0;
    
this.done = []; this.undone = [];
  }
  
History.prototype = {
    
addChange: function(startaddedold) {
      
this.undone.length 0;
      var 
time = +new Datelast this.done[this.done.length 1];
      if (
time this.time 400 || !last ||
          
last.start start added || last.start last.added start last.added last.old.length)
        
this.done.push({startstartaddedaddedoldold});
      else {
        var 
oldoff 0;
        if (
start last.start) {
          for (var 
last.start start 1>= 0; --i)
            
last.old.unshift(old[i]);
          
last.added += last.start start;
          
last.start start;
        }
        else if (
last.start start) {
          
oldoff start last.start;
          
added += oldoff;
        }
        for (var 
last.added oldoffold.lengthe; ++i)
          
last.old.push(old[i]);
        if (
last.added addedlast.added added;
      }
      
this.time time;
    }
  };

  function 
stopMethod() {e_stop(this);}
  
// Ensure an event has a stop method.
  
function addStop(event) {
    if (!
event.stopevent.stop stopMethod;
    return 
event;
  }

  function 
e_preventDefault(e) {
    if (
e.preventDefaulte.preventDefault();
    else 
e.returnValue false;
  }
  function 
e_stopPropagation(e) {
    if (
e.stopPropagatione.stopPropagation();
    else 
e.cancelBubble true;
  }
  function 
e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
  
CodeMirror.e_stop e_stop;
  
CodeMirror.e_preventDefault e_preventDefault;
  
CodeMirror.e_stopPropagation e_stopPropagation;

  function 
e_target(e) {return e.target || e.srcElement;}
  function 
e_button(e) {
    if (
e.which) return e.which;
    else if (
e.button 1) return 1;
    else if (
e.button 2) return 3;
    else if (
e.button 4) return 2;
  }

  
// Event handler registration. If disconnect is true, it'll return a
  // function that unregisters the handler.
  
function connect(nodetypehandlerdisconnect) {
    if (
typeof node.addEventListener == "function") {
      
node.addEventListener(typehandlerfalse);
      if (
disconnect) return function() {node.removeEventListener(typehandlerfalse);};
    }
    else {
      var 
wrapHandler = function(event) {handler(event || window.event);};
      
node.attachEvent("on" typewrapHandler);
      if (
disconnect) return function() {node.detachEvent("on" typewrapHandler);};
    }
  }
  
CodeMirror.connect connect;

  function 
Delayed() {this.id null;}
  
Delayed.prototype = {set: function(msf) {clearTimeout(this.id); this.id setTimeout(fms);}};

  
// Detect drag-and-drop
  
var dragAndDrop = function() {
    
// IE8 has ondragstart and ondrop properties, but doesn't seem to
    // actually support ondragstart the way it's supposed to work.
    
if (/MSIE [1-8]b/.test(navigator.userAgent)) return false;
    var 
div document.createElement('div');
    return 
"draggable" in div;
  }();

  var 
gecko = /gecko/d{7}/i.test(navigator.userAgent);
  var 
ie = /MSIE d/.test(navigator.userAgent);
  var 
webkit = /WebKit//.test(navigator.userAgent);

  
var lineSep "n";
  
// Feature-detect whether newlines in textareas are converted to rn
  
(function () {
    var 
te document.createElement("textarea");
    
te.value "foonbar";
    if (
te.value.indexOf("r") > -1lineSep "rn";
  }());

  
// Counts the column offset in a string, taking tabs into account.
  // Used mostly to find indentation.
  
function countColumn(stringendtabSize) {
    if (
end == null) {
      
end string.search(/[^su00a0]/);
      if (
end == -1end string.length;
    }
    for (var 
00end; ++i) {
      if (
string.charAt(i) == "t"+= tabSize - (tabSize);
      else ++
n;
    }
    return 
n;
  }

  function 
computedStyle(elt) {
    if (
elt.currentStyle) return elt.currentStyle;
    return 
window.getComputedStyle(eltnull);
  }

  
// Find the position of an element by following the offsetParent chain.
  // If screen==true, it returns screen (rather than page) coordinates.
  
function eltOffset(nodescreen) {
    var 
bod node.ownerDocument.body;
    var 
00skipBody false;
    for (var 
nodenn.offsetParent) {
      var 
ol n.offsetLeftot n.offsetTop;
      
// Firefox reports weird inverted offsets when the body has a border.
      
if (== bod) { += Math.abs(ol); += Math.abs(ot); }
      else { 
+= ol+= ot; }
      if (
screen && computedStyle(n).position == "fixed")
        
skipBody true;
    }
    var 
screen && !skipBody null bod;
    for (var 
node.parentNode!= en.parentNode)
      if (
n.scrollLeft != null) { -= n.scrollLeft-= n.scrollTop;}
    return {
leftxtopy};
  }
  
// Use the faster and saner getBoundingClientRect method when possible.
  
if (document.documentElement.getBoundingClientRect != nulleltOffset = function(nodescreen) {
    
// Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
    // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
    
try { var box node.getBoundingClientRect(); box = { topbox.topleftbox.left }; }
    catch(
e) { box = {top0left0}; }
    if (!
screen) {
      
// Get the toplevel scroll, working around browser differences.
      
if (window.pageYOffset == null) {
        var 
document.documentElement || document.body.parentNode;
        if (
t.scrollTop == nulldocument.body;
        
box.top += t.scrollTopbox.left += t.scrollLeft;
      } else {
        
box.top += window.pageYOffsetbox.left += window.pageXOffset;
      }
    }
    return 
box;
  };

  
// Get a node's text content.
  
function eltText(node) {
    return 
node.textContent || node.innerText || node.nodeValue || "";
  }

  
// Operations on {line, ch} objects.
  
function posEq(ab) {return a.line == b.line && a.ch == b.ch;}
  function 
posLess(ab) {return a.line b.line || (a.line == b.line && a.ch b.ch);}
  function 
copyPos(x) {return {linex.linechx.ch};}

  var 
escapeElement document.createElement("pre");
  function 
htmlEscape(str) {
    
escapeElement.textContent str;
    return 
escapeElement.innerHTML;
  }
  
// Recent (late 2011) Opera betas insert bogus newlines at the start
  // of the textContent, so we strip those.
  
if (htmlEscape("a") == "na")
    
htmlEscape = function(str) {
      
escapeElement.textContent str;
      return 
escapeElement.innerHTML.slice(1);
    };
  
// Some IEs don't preserve tabs through innerHTML
  
else if (htmlEscape("t") != "t")
    
htmlEscape = function(str) {
      
escapeElement.innerHTML "";
      
escapeElement.appendChild(document.createTextNode(str));
      return 
escapeElement.innerHTML;
    };
  
CodeMirror.htmlEscape htmlEscape;

  
// Used to position the cursor after an undo/redo by finding the
  // last edited character.
  
function editEnd(fromto) {
    if (!
to) return from from.length 0;
    if (!
from) return to.length;
    for (var 
from.lengthto.length>= && >= 0; --i, --j)
      if (
from.charAt(i) != to.charAt(j)) break;
    return 
1;
  }

  function 
indexOf(collectionelt) {
    if (
collection.indexOf) return collection.indexOf(elt);
    for (var 
0collection.lengthe; ++i)
      if (
collection[i] == elt) return i;
    return -
1;
  }
  function 
isWordChar(ch) {
    return /
w/.test(ch) || ch.toUpperCase() != ch.toLowerCase();
  }

  
// See if "".split is the broken IE version, if so, provide an
  // alternative way to split lines.
  
var splitLines "nnb".split(/n/).length != ? function(string) {
    var 
pos 0nlresult = [];
    while ((
nl string.indexOf("n"pos)) > -1) {
      
result.push(string.slice(posstring.charAt(nl-1) == "r" nl nl));
      
pos nl 1;
    }
    
result.push(string.slice(pos));
    return 
result;
  } : function(string){return 
string.split(/r?n/);};
  
CodeMirror.splitLines splitLines;

  var 
hasSelection window.getSelection ? function(te) {
    try { return 
te.selectionStart != te.selectionEnd; }
    catch(
e) { return false; }
  } : function(
te) {
    try {var 
range te.ownerDocument.selection.createRange();}
    catch(
e) {}
    if (!
range || range.parentElement() != te) return false;
    return 
range.compareEndPoints("StartToEnd"range) != 0;
  };

  
CodeMirror.defineMode("null", function() {
    return {
token: function(stream) {stream.skipToEnd();}};
  });
  
CodeMirror.defineMIME("text/plain""null");

  var 
keyNames = {3"Enter"8"Backspace"9"Tab"13"Enter"16"Shift"17"Ctrl"18"Alt",
                  
19"Pause"20"CapsLock"27"Esc"32"Space"33"PageUp"34"PageDown"35"End",
                  
36"Home"37"Left"38"Up"39"Right"40"Down"44"PrintScrn"45"Insert",
                  
46"Delete"59";"91"Mod"92"Mod"93"Mod"186";"187"="188",",
                  
189"-"190"."191"/"192"`"219"["220"\", 221: "]", 222: "'", 63276: "PageUp",
                  63277: "PageDown", 63275: "End", 63273: "Home", 63234: "Left", 63232: "Up", 63235: "Right",
                  63233: "Down", 63302: "Insert", 63272: "Delete"};
  CodeMirror.keyNames = keyNames;
  (function() {
    // Number keys
    for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
    // Alphabetic keys
    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
    // Function keys
    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
  })();

  return CodeMirror;
})();
?>
Онлайн: 1
Реклама