Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(586)

Side by Side Diff: Source/devtools/front_end/cm/codemirror.js

Issue 23496039: DevTools: [CodeMirror] roll CodeMirror to @e0b0e32ed (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/devtools/front_end/cm/codemirror.css ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // CodeMirror is the only global var we claim 1 // CodeMirror is the only global var we claim
2 window.CodeMirror = (function() { 2 window.CodeMirror = (function() {
3 "use strict"; 3 "use strict";
4 4
5 // BROWSER SNIFFING 5 // BROWSER SNIFFING
6 6
7 // Crude, but necessary to handle a number of hard-to-feature-detect 7 // Crude, but necessary to handle a number of hard-to-feature-detect
8 // bugs and behavior differences. 8 // bugs and behavior differences.
9 var gecko = /gecko\/\d/i.test(navigator.userAgent); 9 var gecko = /gecko\/\d/i.test(navigator.userAgent);
10 var ie = /MSIE \d/.test(navigator.userAgent); 10 var ie = /MSIE \d/.test(navigator.userAgent);
11 var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8 ); 11 var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8 );
12 var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9 ); 12 var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9 );
13 var webkit = /WebKit\//.test(navigator.userAgent); 13 var webkit = /WebKit\//.test(navigator.userAgent);
14 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); 14 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
15 var chrome = /Chrome\//.test(navigator.userAgent); 15 var chrome = /Chrome\//.test(navigator.userAgent);
16 var opera = /Opera\//.test(navigator.userAgent); 16 var opera = /Opera\//.test(navigator.userAgent);
17 var safari = /Apple Computer/.test(navigator.vendor); 17 var safari = /Apple Computer/.test(navigator.vendor);
18 var khtml = /KHTML\//.test(navigator.userAgent); 18 var khtml = /KHTML\//.test(navigator.userAgent);
19 var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent); 19 var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent);
20 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAge nt); 20 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAge nt);
21 var phantom = /PhantomJS/.test(navigator.userAgent); 21 var phantom = /PhantomJS/.test(navigator.userAgent);
22 22
23 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(naviga tor.userAgent); 23 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(naviga tor.userAgent);
24 // This is woefully incomplete. Suggestions for alternative methods welcome. 24 // This is woefully incomplete. Suggestions for alternative methods welcome.
25 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i .test(navigator.userAgent); 25 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i .test(navigator.userAgent);
26 var mac = ios || /Mac/.test(navigator.platform); 26 var mac = ios || /Mac/.test(navigator.platform);
27 var windows = /windows/i.test(navigator.platform); 27 var windows = /win/i.test(navigator.platform);
28 28
29 var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/); 29 var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
30 if (opera_version) opera_version = Number(opera_version[1]); 30 if (opera_version) opera_version = Number(opera_version[1]);
31 if (opera_version && opera_version >= 15) { opera = false; webkit = true; } 31 if (opera_version && opera_version >= 15) { opera = false; webkit = true; }
32 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X 32 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
33 var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera _version < 12.11)); 33 var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera _version < 12.11));
34 var captureMiddleClick = gecko || (ie && !ie_lt9); 34 var captureMiddleClick = gecko || (ie && !ie_lt9);
35 35
36 // Optimize some code when these features are not used 36 // Optimize some code when these features are not used
37 var sawReadOnlySpans = false, sawCollapsedSpans = false; 37 var sawReadOnlySpans = false, sawCollapsedSpans = false;
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 if (len > d.maxLineLength) { 297 if (len > d.maxLineLength) {
298 d.maxLineLength = len; 298 d.maxLineLength = len;
299 d.maxLine = line; 299 d.maxLine = line;
300 } 300 }
301 }); 301 });
302 } 302 }
303 303
304 // Make sure the gutters options contains the element 304 // Make sure the gutters options contains the element
305 // "CodeMirror-linenumbers" when the lineNumbers option is true. 305 // "CodeMirror-linenumbers" when the lineNumbers option is true.
306 function setGuttersForLineNumbers(options) { 306 function setGuttersForLineNumbers(options) {
307 var found = false; 307 var found = indexOf(options.gutters, "CodeMirror-linenumbers");
308 for (var i = 0; i < options.gutters.length; ++i) { 308 if (found == -1 && options.lineNumbers) {
309 if (options.gutters[i] == "CodeMirror-linenumbers") { 309 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
310 if (options.lineNumbers) found = true; 310 } else if (found > -1 && !options.lineNumbers) {
311 else options.gutters.splice(i--, 1); 311 options.gutters = options.gutters.slice(0);
312 } 312 options.gutters.splice(i, 1);
313 } 313 }
314 if (!found && options.lineNumbers)
315 options.gutters.push("CodeMirror-linenumbers");
316 } 314 }
317 315
318 // SCROLLBARS 316 // SCROLLBARS
319 317
320 // Re-synchronize the fake scrollbars with the actual size of the 318 // Re-synchronize the fake scrollbars with the actual size of the
321 // content. Optionally force a scrollTop. 319 // content. Optionally force a scrollTop.
322 function updateScrollbars(cm) { 320 function updateScrollbars(cm) {
323 var d = cm.display, docHeight = cm.doc.height; 321 var d = cm.display, docHeight = cm.doc.height;
324 var totalHeight = docHeight + paddingVert(d); 322 var totalHeight = docHeight + paddingVert(d);
325 d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; 323 d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px";
326 d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scr ollerCutOff) + "px"; 324 d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scr ollerCutOff) + "px";
327 var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); 325 var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight);
328 var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1); 326 var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1);
329 var needsV = scrollHeight > (d.scroller.clientHeight + 1); 327 var needsV = scrollHeight > (d.scroller.clientHeight + 1);
330 if (needsV) { 328 if (needsV) {
331 d.scrollbarV.style.display = "block"; 329 d.scrollbarV.style.display = "block";
332 d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0 "; 330 d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0 ";
333 d.scrollbarV.firstChild.style.height = 331 d.scrollbarV.firstChild.style.height =
334 (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + " px"; 332 (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + " px";
335 } else d.scrollbarV.style.display = ""; 333 } else {
334 d.scrollbarV.style.display = "";
335 d.scrollbarV.firstChild.style.height = "0";
336 }
336 if (needsH) { 337 if (needsH) {
337 d.scrollbarH.style.display = "block"; 338 d.scrollbarH.style.display = "block";
338 d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0" ; 339 d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0" ;
339 d.scrollbarH.firstChild.style.width = 340 d.scrollbarH.firstChild.style.width =
340 (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWi dth) + "px"; 341 (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWi dth) + "px";
341 } else d.scrollbarH.style.display = ""; 342 } else {
343 d.scrollbarH.style.display = "";
344 d.scrollbarH.firstChild.style.width = "0";
345 }
342 if (needsH && needsV) { 346 if (needsH && needsV) {
343 d.scrollbarFiller.style.display = "block"; 347 d.scrollbarFiller.style.display = "block";
344 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbar Width(d.measure) + "px"; 348 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbar Width(d.measure) + "px";
345 } else d.scrollbarFiller.style.display = ""; 349 } else d.scrollbarFiller.style.display = "";
346 if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutte r) { 350 if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutte r) {
347 d.gutterFiller.style.display = "block"; 351 d.gutterFiller.style.display = "block";
348 d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; 352 d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px";
349 d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; 353 d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
350 } else d.gutterFiller.style.display = ""; 354 } else d.gutterFiller.style.display = "";
351 355
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 function compensateForHScroll(display) { 403 function compensateForHScroll(display) {
400 return getRect(display.scroller).left - getRect(display.sizer).left; 404 return getRect(display.scroller).left - getRect(display.sizer).left;
401 } 405 }
402 406
403 // DISPLAY DRAWING 407 // DISPLAY DRAWING
404 408
405 function updateDisplay(cm, changes, viewPort, forced) { 409 function updateDisplay(cm, changes, viewPort, forced) {
406 var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; 410 var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated;
407 var visible = visibleLines(cm.display, cm.doc, viewPort); 411 var visible = visibleLines(cm.display, cm.doc, viewPort);
408 for (;;) { 412 for (;;) {
413 var oldWidth = cm.display.scroller.clientWidth;
409 if (!updateDisplayInner(cm, changes, visible, forced)) break; 414 if (!updateDisplayInner(cm, changes, visible, forced)) break;
410 forced = false;
411 updated = true; 415 updated = true;
416 changes = [];
412 updateSelection(cm); 417 updateSelection(cm);
413 updateScrollbars(cm); 418 updateScrollbars(cm);
419 if (cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth ) {
420 forced = true;
421 continue;
422 }
423 forced = false;
414 424
415 // Clip forced viewport to actual scrollable area 425 // Clip forced viewport to actual scrollable area
416 if (viewPort) 426 if (viewPort)
417 viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroll er.clientHeight, 427 viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroll er.clientHeight,
418 typeof viewPort == "number" ? viewPort : viewPort.to p); 428 typeof viewPort == "number" ? viewPort : viewPort.to p);
419 visible = visibleLines(cm.display, cm.doc, viewPort); 429 visible = visibleLines(cm.display, cm.doc, viewPort);
420 if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.sho wingTo) 430 if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.sho wingTo)
421 break; 431 break;
422 changes = [];
423 } 432 }
424 433
425 if (updated) { 434 if (updated) {
426 signalLater(cm, "update", cm); 435 signalLater(cm, "update", cm);
427 if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) 436 if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo)
428 signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display .showingTo); 437 signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display .showingTo);
429 } 438 }
430 return updated; 439 return updated;
431 } 440 }
432 441
(...skipping 15 matching lines...) Expand all
448 457
449 if (maybeUpdateLineNumberWidth(cm)) 458 if (maybeUpdateLineNumberWidth(cm))
450 changes = [{from: doc.first, to: doc.first + doc.size}]; 459 changes = [{from: doc.first, to: doc.first + doc.size}];
451 var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px"; 460 var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px";
452 display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0"; 461 display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0";
453 462
454 // Used to determine which lines need their line numbers updated 463 // Used to determine which lines need their line numbers updated
455 var positionsChangedFrom = Infinity; 464 var positionsChangedFrom = Infinity;
456 if (cm.options.lineNumbers) 465 if (cm.options.lineNumbers)
457 for (var i = 0; i < changes.length; ++i) 466 for (var i = 0; i < changes.length; ++i)
458 if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; } 467 if (changes[i].diff && changes[i].from < positionsChangedFrom) { positio nsChangedFrom = changes[i].from; }
459 468
460 var end = doc.first + doc.size; 469 var end = doc.first + doc.size;
461 var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); 470 var from = Math.max(visible.from - cm.options.viewportMargin, doc.first);
462 var to = Math.min(end, visible.to + cm.options.viewportMargin); 471 var to = Math.min(end, visible.to + cm.options.viewportMargin);
463 if (display.showingFrom < from && from - display.showingFrom < 20) from = Ma th.max(doc.first, display.showingFrom); 472 if (display.showingFrom < from && from - display.showingFrom < 20) from = Ma th.max(doc.first, display.showingFrom);
464 if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end , display.showingTo); 473 if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end , display.showingTo);
465 if (sawCollapsedSpans) { 474 if (sawCollapsedSpans) {
466 from = lineNo(visualLine(doc, getLine(doc, from))); 475 from = lineNo(visualLine(doc, getLine(doc, from)));
467 while (to < end && lineIsHidden(doc, getLine(doc, to))) ++to; 476 while (to < end && lineIsHidden(doc, getLine(doc, to))) ++to;
468 } 477 }
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 node.parentNode.removeChild(node); 614 node.parentNode.removeChild(node);
606 } 615 }
607 return next; 616 return next;
608 } 617 }
609 618
610 var nextIntact = intact.shift(), lineN = from; 619 var nextIntact = intact.shift(), lineN = from;
611 cm.doc.iter(from, to, function(line) { 620 cm.doc.iter(from, to, function(line) {
612 if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift(); 621 if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift();
613 if (lineIsHidden(cm.doc, line)) { 622 if (lineIsHidden(cm.doc, line)) {
614 if (line.height != 0) updateLineHeight(line, 0); 623 if (line.height != 0) updateLineHeight(line, 0);
615 if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widget s.length; ++i) { 624 if (line.widgets && cur && cur.previousSibling) for (var i = 0; i < line .widgets.length; ++i) {
616 var w = line.widgets[i]; 625 var w = line.widgets[i];
617 if (w.showIfHidden) { 626 if (w.showIfHidden) {
618 var prev = cur.previousSibling; 627 var prev = cur.previousSibling;
619 if (/pre/i.test(prev.nodeName)) { 628 if (/pre/i.test(prev.nodeName)) {
620 var wrap = elt("div", null, null, "position: relative"); 629 var wrap = elt("div", null, null, "position: relative");
621 prev.parentNode.replaceChild(wrap, prev); 630 prev.parentNode.replaceChild(wrap, prev);
622 wrap.appendChild(prev); 631 wrap.appendChild(prev);
623 prev = wrap; 632 prev = wrap;
624 } 633 }
625 var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewi dget")); 634 var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewi dget"));
(...skipping 24 matching lines...) Expand all
650 } 659 }
651 660
652 lineNode.lineObj = line; 661 lineNode.lineObj = line;
653 } 662 }
654 ++lineN; 663 ++lineN;
655 }); 664 });
656 while (cur) cur = rm(cur); 665 while (cur) cur = rm(cur);
657 } 666 }
658 667
659 function buildLineElement(cm, line, lineNo, dims, reuse) { 668 function buildLineElement(cm, line, lineNo, dims, reuse) {
660 var lineElement = lineContent(cm, line); 669 var built = buildLineContent(cm, line), lineElement = built.pre;
661 var markers = line.gutterMarkers, display = cm.display, wrap; 670 var markers = line.gutterMarkers, display = cm.display, wrap;
662 671
663 if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass && !line.widgets) 672 var bgClass = built.bgClass ? built.bgClass + " " + (line.bgClass || "") : l ine.bgClass;
673 if (!cm.options.lineNumbers && !markers && !bgClass && !line.wrapClass && !l ine.widgets)
664 return lineElement; 674 return lineElement;
665 675
666 // Lines with gutter elements, widgets or a background class need 676 // Lines with gutter elements, widgets or a background class need
667 // to be wrapped again, and have the extra elements added to the 677 // to be wrapped again, and have the extra elements added to the
668 // wrapper div 678 // wrapper div
669 679
670 if (reuse) { 680 if (reuse) {
671 reuse.alignable = null; 681 reuse.alignable = null;
672 var isOk = true, widgetsSeen = 0, insertBefore = null; 682 var isOk = true, widgetsSeen = 0, insertBefore = null;
673 for (var n = reuse.firstChild, next; n; n = next) { 683 for (var n = reuse.firstChild, next; n; n = next) {
(...skipping 17 matching lines...) Expand all
691 if (isOk && widgetsSeen == line.widgets.length) { 701 if (isOk && widgetsSeen == line.widgets.length) {
692 wrap = reuse; 702 wrap = reuse;
693 reuse.className = line.wrapClass || ""; 703 reuse.className = line.wrapClass || "";
694 } 704 }
695 } 705 }
696 if (!wrap) { 706 if (!wrap) {
697 wrap = elt("div", null, line.wrapClass, "position: relative"); 707 wrap = elt("div", null, line.wrapClass, "position: relative");
698 wrap.appendChild(lineElement); 708 wrap.appendChild(lineElement);
699 } 709 }
700 // Kludge to make sure the styled element lies behind the selection (by z-in dex) 710 // Kludge to make sure the styled element lies behind the selection (by z-in dex)
701 if (line.bgClass) 711 if (bgClass)
702 wrap.insertBefore(elt("div", null, line.bgClass + " CodeMirror-linebackgro und"), wrap.firstChild); 712 wrap.insertBefore(elt("div", null, bgClass + " CodeMirror-linebackground") , wrap.firstChild);
703 if (cm.options.lineNumbers || markers) { 713 if (cm.options.lineNumbers || markers) {
704 var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absol ute; left: " + 714 var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absol ute; left: " +
705 (cm.options.fixedGutter ? dims.fixe dPos : -dims.gutterTotalWidth) + "px"), 715 (cm.options.fixedGutter ? dims.fixe dPos : -dims.gutterTotalWidth) + "px"),
706 wrap.firstChild); 716 wrap.firstChild);
707 if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push (gutterWrap); 717 if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push (gutterWrap);
708 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumber s"])) 718 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumber s"]))
709 wrap.lineNumber = gutterWrap.appendChild( 719 wrap.lineNumber = gutterWrap.appendChild(
710 elt("div", lineNumberFor(cm.options, lineNo), 720 elt("div", lineNumberFor(cm.options, lineNo),
711 "CodeMirror-linenumber CodeMirror-gutter-elt", 721 "CodeMirror-linenumber CodeMirror-gutter-elt",
712 "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " 722 "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
864 display.selectionDiv.style.display = ""; 874 display.selectionDiv.style.display = "";
865 } 875 }
866 876
867 // Cursor-blinking 877 // Cursor-blinking
868 function restartBlink(cm) { 878 function restartBlink(cm) {
869 if (!cm.state.focused) return; 879 if (!cm.state.focused) return;
870 var display = cm.display; 880 var display = cm.display;
871 clearInterval(display.blinker); 881 clearInterval(display.blinker);
872 var on = true; 882 var on = true;
873 display.cursor.style.visibility = display.otherCursor.style.visibility = ""; 883 display.cursor.style.visibility = display.otherCursor.style.visibility = "";
874 display.blinker = setInterval(function() { 884 if (cm.options.cursorBlinkRate > 0)
875 display.cursor.style.visibility = display.otherCursor.style.visibility = ( on = !on) ? "" : "hidden"; 885 display.blinker = setInterval(function() {
876 }, cm.options.cursorBlinkRate); 886 display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden";
887 }, cm.options.cursorBlinkRate);
877 } 888 }
878 889
879 // HIGHLIGHT WORKER 890 // HIGHLIGHT WORKER
880 891
881 function startWorker(cm, time) { 892 function startWorker(cm, time) {
882 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo) 893 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo)
883 cm.state.highlight.set(time, bind(highlightWorker, cm)); 894 cm.state.highlight.set(time, bind(highlightWorker, cm));
884 } 895 }
885 896
886 function highlightWorker(cm) { 897 function highlightWorker(cm) {
(...skipping 30 matching lines...) Expand all
917 regChange(this, changed[i].start, changed[i].end); 928 regChange(this, changed[i].start, changed[i].end);
918 })(); 929 })();
919 } 930 }
920 931
921 // Finds the line to start with when starting a parse. Tries to 932 // Finds the line to start with when starting a parse. Tries to
922 // find a line with a stateAfter, so that it can start with a 933 // find a line with a stateAfter, so that it can start with a
923 // valid state. If that fails, it returns the line with the 934 // valid state. If that fails, it returns the line with the
924 // smallest indentation, which tends to need the least context to 935 // smallest indentation, which tends to need the least context to
925 // parse correctly. 936 // parse correctly.
926 function findStartLine(cm, n, precise) { 937 function findStartLine(cm, n, precise) {
927 var minindent, minline, doc = cm.doc; 938 var minindent, minline, doc = cm.doc, maxScan = cm.doc.mode.innerMode ? 1000 : 100;
928 for (var search = n, lim = n - 100; search > lim; --search) { 939 for (var search = n, lim = n - maxScan; search > lim; --search) {
929 if (search <= doc.first) return doc.first; 940 if (search <= doc.first) return doc.first;
930 var line = getLine(doc, search - 1); 941 var line = getLine(doc, search - 1);
931 if (line.stateAfter && (!precise || search <= doc.frontier)) return search ; 942 if (line.stateAfter && (!precise || search <= doc.frontier)) return search ;
932 var indented = countColumn(line.text, null, cm.options.tabSize); 943 var indented = countColumn(line.text, null, cm.options.tabSize);
933 if (minline == null || minindent > indented) { 944 if (minline == null || minindent > indented) {
934 minline = search - 1; 945 minline = search - 1;
935 minindent = indented; 946 minindent = indented;
936 } 947 }
937 } 948 }
938 return minline; 949 return minline;
939 } 950 }
940 951
941 function getStateBefore(cm, n, precise) { 952 function getStateBefore(cm, n, precise) {
942 var doc = cm.doc, display = cm.display; 953 var doc = cm.doc, display = cm.display;
943 if (!doc.mode.startState) return true; 954 if (!doc.mode.startState) return true;
944 var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine( doc, pos-1).stateAfter; 955 var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine( doc, pos-1).stateAfter;
945 if (!state) state = startState(doc.mode); 956 if (!state) state = startState(doc.mode);
946 else state = copyState(doc.mode, state); 957 else state = copyState(doc.mode, state);
947 doc.iter(pos, n, function(line) { 958 doc.iter(pos, n, function(line) {
948 processLine(cm, line, state); 959 processLine(cm, line, state);
949 var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && p os < display.showingTo; 960 var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && p os < display.showingTo;
950 line.stateAfter = save ? copyState(doc.mode, state) : null; 961 line.stateAfter = save ? copyState(doc.mode, state) : null;
951 ++pos; 962 ++pos;
952 }); 963 });
953 return state; 964 return state;
954 } 965 }
955 966
956 // POSITION MEASUREMENT 967 // POSITION MEASUREMENT
957 968
958 function paddingTop(display) {return display.lineSpace.offsetTop;} 969 function paddingTop(display) {return display.lineSpace.offsetTop;}
959 function paddingVert(display) {return display.mover.offsetHeight - display.lin eSpace.offsetHeight;} 970 function paddingVert(display) {return display.mover.offsetHeight - display.lin eSpace.offsetHeight;}
960 function paddingLeft(display) { 971 function paddingLeft(display) {
961 var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-a lign: left")).appendChild(elt("span", "x")); 972 var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-a lign: left")).appendChild(elt("span", "x"));
962 return e.offsetLeft; 973 return e.offsetLeft;
963 } 974 }
964 975
965 function measureChar(cm, line, ch, data, bias) { 976 function measureChar(cm, line, ch, data, bias) {
966 var dir = -1; 977 var dir = -1;
967 data = data || measureLine(cm, line); 978 data = data || measureLine(cm, line);
979 if (data.crude) {
980 var left = data.left + ch * data.width;
981 return {left: left, right: left + data.width, top: data.top, bottom: data. bottom};
982 }
968 983
969 for (var pos = ch;; pos += dir) { 984 for (var pos = ch;; pos += dir) {
970 var r = data.get(pos); 985 var r = data[pos];
971 if (r) break; 986 if (r) break;
972 if (dir < 0 && pos == 0) dir = 1; 987 if (dir < 0 && pos == 0) dir = 1;
973 } 988 }
974 bias = pos > ch ? "left" : pos < ch ? "right" : bias; 989 bias = pos > ch ? "left" : pos < ch ? "right" : bias;
975 if (bias == "left" && r.leftSide) r = r.leftSide; 990 if (bias == "left" && r.leftSide) r = r.leftSide;
976 else if (bias == "right" && r.rightSide) r = r.rightSide; 991 else if (bias == "right" && r.rightSide) r = r.rightSide;
977 return {left: pos < ch ? r.right : r.left, 992 return {left: pos < ch ? r.right : r.left,
978 right: pos > ch ? r.left : r.right, 993 right: pos > ch ? r.left : r.right,
979 top: r.top, 994 top: r.top,
980 bottom: r.bottom}; 995 bottom: r.bottom};
(...skipping 14 matching lines...) Expand all
995 var exists = findCachedMeasurement(cm, line); 1010 var exists = findCachedMeasurement(cm, line);
996 if (exists) exists.text = exists.measure = exists.markedSpans = null; 1011 if (exists) exists.text = exists.measure = exists.markedSpans = null;
997 } 1012 }
998 1013
999 function measureLine(cm, line) { 1014 function measureLine(cm, line) {
1000 // First look in the cache 1015 // First look in the cache
1001 var cached = findCachedMeasurement(cm, line); 1016 var cached = findCachedMeasurement(cm, line);
1002 if (cached) return cached.measure; 1017 if (cached) return cached.measure;
1003 1018
1004 // Failing that, recompute and store result in cache 1019 // Failing that, recompute and store result in cache
1005 var measure = measureLineInner(cm, line, 0, 10); 1020 var measure = measureLineInner(cm, line);
1006 measure.get = function(num) {
1007 if (this[num]) return this[num];
1008 if (num < 0 || num >= line.text.length) return null;
1009 measureLineInner(cm, line, Math.max(num - 50, 0), Math.min(num + 50, line. text.length), this);
1010 return this[num];
1011 };
1012 var cache = cm.display.measureLineCache; 1021 var cache = cm.display.measureLineCache;
1013 var memo = {text: line.text, width: cm.display.scroller.clientWidth, 1022 var memo = {text: line.text, width: cm.display.scroller.clientWidth,
1014 markedSpans: line.markedSpans, measure: measure, 1023 markedSpans: line.markedSpans, measure: measure,
1015 classes: line.textClass + "|" + line.bgClass + "|" + line.wrapCl ass}; 1024 classes: line.textClass + "|" + line.bgClass + "|" + line.wrapCl ass};
1016 if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; 1025 if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo;
1017 else cache.push(memo); 1026 else cache.push(memo);
1018 return measure; 1027 return measure;
1019 } 1028 }
1020 1029
1021 function measureLineInner(cm, line, from, to, oldMeasure) { 1030 function measureLineInner(cm, line) {
1031 if (!cm.options.lineWrapping && line.text.length >= cm.options.crudeMeasurin gFrom)
1032 return crudelyMeasureLine(cm, line);
1033
1022 var display = cm.display, measure = emptyArray(line.text.length); 1034 var display = cm.display, measure = emptyArray(line.text.length);
1023 var pre = lineContent(cm, line, measure, true, from, to); 1035 var pre = buildLineContent(cm, line, measure, true).pre;
1024 1036
1025 // IE does not cache element positions of inline elements between 1037 // IE does not cache element positions of inline elements between
1026 // calls to getBoundingClientRect. This makes the loop below, 1038 // calls to getBoundingClientRect. This makes the loop below,
1027 // which gathers the positions of all the characters on the line, 1039 // which gathers the positions of all the characters on the line,
1028 // do an amount of layout work quadratic to the number of 1040 // do an amount of layout work quadratic to the number of
1029 // characters. When line wrapping is off, we try to improve things 1041 // characters. When line wrapping is off, we try to improve things
1030 // by first subdividing the line into a bunch of inline blocks, so 1042 // by first subdividing the line into a bunch of inline blocks, so
1031 // that IE can reuse most of the layout information from caches 1043 // that IE can reuse most of the layout information from caches
1032 // for those blocks. This does interfere with line wrapping, so it 1044 // for those blocks. This does interfere with line wrapping, so it
1033 // doesn't work when wrapping is on, but in that case the 1045 // doesn't work when wrapping is on, but in that case the
1034 // situation is slightly better, since IE does cache line-wrapping 1046 // situation is slightly better, since IE does cache line-wrapping
1035 // information and only recomputes per-line. 1047 // information and only recomputes per-line.
1036 if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100 ) { 1048 if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100 ) {
1037 var fragment = document.createDocumentFragment(); 1049 var fragment = document.createDocumentFragment();
1038 var chunk = 10, n = pre.childNodes.length; 1050 var chunk = 10, n = pre.childNodes.length;
1039 for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) { 1051 for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
1040 var wrap = elt("div", null, null, "display: inline-block"); 1052 var wrap = elt("div", null, null, "display: inline-block");
1041 for (var j = 0; j < chunk && n; ++j) { 1053 for (var j = 0; j < chunk && n; ++j) {
1042 wrap.appendChild(pre.firstChild); 1054 wrap.appendChild(pre.firstChild);
1043 --n; 1055 --n;
1044 } 1056 }
1045 fragment.appendChild(wrap); 1057 fragment.appendChild(wrap);
1046 } 1058 }
1047 pre.appendChild(fragment); 1059 pre.appendChild(fragment);
1048 } 1060 }
1049 1061
1050 removeChildrenAndAdd(display.measure, pre); 1062 removeChildrenAndAdd(display.measure, pre);
1051 1063
1052 var outer = getRect(display.lineDiv); 1064 var outer = getRect(display.lineDiv);
1053 var vranges = [], data = oldMeasure || emptyArray(line.text.length), maxBot = pre.offsetHeight; 1065 var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHe ight;
1054 // Work around an IE7/8 bug where it will sometimes have randomly 1066 // Work around an IE7/8 bug where it will sometimes have randomly
1055 // replaced our pre with a clone at this point. 1067 // replaced our pre with a clone at this point.
1056 if (ie_lt9 && display.measure.first != pre) 1068 if (ie_lt9 && display.measure.first != pre)
1057 removeChildrenAndAdd(display.measure, pre); 1069 removeChildrenAndAdd(display.measure, pre);
1058 1070
1059 function measureRect(rect) { 1071 function measureRect(rect) {
1060 var top = rect.top - outer.top, bot = rect.bottom - outer.top; 1072 var top = rect.top - outer.top, bot = rect.bottom - outer.top;
1061 if (bot > maxBot) bot = maxBot; 1073 if (bot > maxBot) bot = maxBot;
1062 if (top < 0) top = 0; 1074 if (top < 0) top = 0;
1063 for (var i = vranges.length - 2; i >= 0; i -= 2) { 1075 for (var i = vranges.length - 2; i >= 0; i -= 2) {
(...skipping 25 matching lines...) Expand all
1089 var rects = node.getClientRects(); 1101 var rects = node.getClientRects();
1090 if (rects.length > 1) { 1102 if (rects.length > 1) {
1091 rect = data[i] = measureRect(rects[0]); 1103 rect = data[i] = measureRect(rects[0]);
1092 rect.rightSide = measureRect(rects[rects.length - 1]); 1104 rect.rightSide = measureRect(rects[rects.length - 1]);
1093 } 1105 }
1094 } 1106 }
1095 if (!rect) rect = data[i] = measureRect(getRect(node)); 1107 if (!rect) rect = data[i] = measureRect(getRect(node));
1096 if (cur.measureRight) rect.right = getRect(cur.measureRight).left; 1108 if (cur.measureRight) rect.right = getRect(cur.measureRight).left;
1097 if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide)); 1109 if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide));
1098 } 1110 }
1099 for (var i = 0, cur; i < data.length; ++i) if (measure[i] && (cur = data[i]) ) { 1111 removeChildren(cm.display.measure);
1112 for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) {
1100 finishRect(cur); 1113 finishRect(cur);
1101 if (cur.leftSide) finishRect(cur.leftSide); 1114 if (cur.leftSide) finishRect(cur.leftSide);
1102 if (cur.rightSide) finishRect(cur.rightSide); 1115 if (cur.rightSide) finishRect(cur.rightSide);
1103 } 1116 }
1104 return data; 1117 return data;
1105 } 1118 }
1106 1119
1120 function crudelyMeasureLine(cm, line) {
1121 var copy = new Line(line.text.slice(0, 100), null);
1122 if (line.textClass) copy.textClass = line.textClass;
1123 var measure = measureLineInner(cm, copy);
1124 var left = measureChar(cm, copy, 0, measure, "left");
1125 var right = measureChar(cm, copy, 99, measure, "right");
1126 return {crude: true, top: left.top, left: left.left, bottom: left.bottom, wi dth: (right.right - left.left) / 100};
1127 }
1128
1107 function measureLineWidth(cm, line) { 1129 function measureLineWidth(cm, line) {
1108 var hasBadSpan = false; 1130 var hasBadSpan = false;
1109 if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) { 1131 if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) {
1110 var sp = line.markedSpans[i]; 1132 var sp = line.markedSpans[i];
1111 if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSp an = true; 1133 if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSp an = true;
1112 } 1134 }
1113 var cached = !hasBadSpan && findCachedMeasurement(cm, line); 1135 var cached = !hasBadSpan && findCachedMeasurement(cm, line);
1114 if (cached) return measureChar(cm, line, line.text.length, cached.measure, " right").right; 1136 if (cached || line.text.length >= cm.options.crudeMeasuringFrom)
1137 return measureChar(cm, line, line.text.length, cached && cached.measure, " right").right;
1115 1138
1116 var pre = lineContent(cm, line, null, true); 1139 var pre = buildLineContent(cm, line, null, true).pre;
1117 var end = pre.appendChild(zeroWidthElement(cm.display.measure)); 1140 var end = pre.appendChild(zeroWidthElement(cm.display.measure));
1118 removeChildrenAndAdd(cm.display.measure, pre); 1141 removeChildrenAndAdd(cm.display.measure, pre);
1119 return getRect(end).right - getRect(cm.display.lineDiv).left; 1142 return getRect(end).right - getRect(cm.display.lineDiv).left;
1120 } 1143 }
1121 1144
1122 function clearCaches(cm) { 1145 function clearCaches(cm) {
1123 cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; 1146 cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0;
1124 cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; 1147 cm.display.cachedCharWidth = cm.display.cachedTextHeight = null;
1125 if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; 1148 if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
1126 cm.display.lineNumChars = null; 1149 cm.display.lineNumChars = null;
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after
1591 function drag_(e) { 1614 function drag_(e) {
1592 if (signalDOMEvent(cm, e) || cm.options.onDragEvent && cm.options.onDragEv ent(cm, addStop(e))) return; 1615 if (signalDOMEvent(cm, e) || cm.options.onDragEvent && cm.options.onDragEv ent(cm, addStop(e))) return;
1593 e_stop(e); 1616 e_stop(e);
1594 } 1617 }
1595 if (cm.options.dragDrop) { 1618 if (cm.options.dragDrop) {
1596 on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); 1619 on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
1597 on(d.scroller, "dragenter", drag_); 1620 on(d.scroller, "dragenter", drag_);
1598 on(d.scroller, "dragover", drag_); 1621 on(d.scroller, "dragover", drag_);
1599 on(d.scroller, "drop", operation(cm, onDrop)); 1622 on(d.scroller, "drop", operation(cm, onDrop));
1600 } 1623 }
1601 on(d.scroller, "paste", function(e){ 1624 on(d.scroller, "paste", function(e) {
1602 if (eventInWidget(d, e)) return; 1625 if (eventInWidget(d, e)) return;
1603 focusInput(cm); 1626 focusInput(cm);
1604 fastPoll(cm); 1627 fastPoll(cm);
1605 }); 1628 });
1606 on(d.input, "paste", function() { 1629 on(d.input, "paste", function() {
1607 // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 1630 // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
1608 // Add a char to the end of textarea before paste occur so that 1631 // Add a char to the end of textarea before paste occur so that
1609 // selection doesn't span to the end of textarea. 1632 // selection doesn't span to the end of textarea.
1610 if (webkit && !cm.state.fakedLastChar) { 1633 if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleD own < 200)) {
1611 var start = d.input.selectionStart, end = d.input.selectionEnd; 1634 var start = d.input.selectionStart, end = d.input.selectionEnd;
1612 d.input.value += "$"; 1635 d.input.value += "$";
1613 d.input.selectionStart = start; 1636 d.input.selectionStart = start;
1614 d.input.selectionEnd = end; 1637 d.input.selectionEnd = end;
1615 cm.state.fakedLastChar = true; 1638 cm.state.fakedLastChar = true;
1616 } 1639 }
1617 cm.state.pasteIncoming = true; 1640 cm.state.pasteIncoming = true;
1618 fastPoll(cm); 1641 fastPoll(cm);
1619 }); 1642 });
1620 1643
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1670 return; 1693 return;
1671 } 1694 }
1672 if (clickInGutter(cm, e)) return; 1695 if (clickInGutter(cm, e)) return;
1673 var start = posFromMouse(cm, e); 1696 var start = posFromMouse(cm, e);
1674 1697
1675 switch (e_button(e)) { 1698 switch (e_button(e)) {
1676 case 3: 1699 case 3:
1677 if (captureMiddleClick) onContextMenu.call(cm, cm, e); 1700 if (captureMiddleClick) onContextMenu.call(cm, cm, e);
1678 return; 1701 return;
1679 case 2: 1702 case 2:
1703 if (webkit) cm.state.lastMiddleDown = +new Date;
1680 if (start) extendSelection(cm.doc, start); 1704 if (start) extendSelection(cm.doc, start);
1681 setTimeout(bind(focusInput, cm), 20); 1705 setTimeout(bind(focusInput, cm), 20);
1682 e_preventDefault(e); 1706 e_preventDefault(e);
1683 return; 1707 return;
1684 } 1708 }
1685 // For button 1, if it was clicked inside the editor 1709 // For button 1, if it was clicked inside the editor
1686 // (posFromMouse returning non-null), we have to adjust the 1710 // (posFromMouse returning non-null), we have to adjust the
1687 // selection. 1711 // selection.
1688 if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); retur n;} 1712 if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); retur n;}
1689 1713
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1790 1814
1791 var move = operation(cm, function(e) { 1815 var move = operation(cm, function(e) {
1792 if (!ie && !e_button(e)) done(e); 1816 if (!ie && !e_button(e)) done(e);
1793 else extend(e); 1817 else extend(e);
1794 }); 1818 });
1795 var up = operation(cm, done); 1819 var up = operation(cm, done);
1796 on(document, "mousemove", move); 1820 on(document, "mousemove", move);
1797 on(document, "mouseup", up); 1821 on(document, "mouseup", up);
1798 } 1822 }
1799 1823
1800 function clickInGutter(cm, e) { 1824 function gutterEvent(cm, e, type, prevent, signalfn) {
1801 var display = cm.display;
1802 try { var mX = e.clientX, mY = e.clientY; } 1825 try { var mX = e.clientX, mY = e.clientY; }
1803 catch(e) { return false; } 1826 catch(e) { return false; }
1827 if (mX >= Math.floor(getRect(cm.display.gutters).right)) return false;
1828 if (prevent) e_preventDefault(e);
1804 1829
1805 if (mX >= Math.floor(getRect(display.gutters).right)) return false; 1830 var display = cm.display;
1806 e_preventDefault(e); 1831 var lineBox = getRect(display.lineDiv);
1807 if (!hasHandler(cm, "gutterClick")) return true;
1808 1832
1809 var lineBox = getRect(display.lineDiv); 1833 if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented( e);
1810 if (mY > lineBox.bottom) return true;
1811 mY -= lineBox.top - display.viewOffset; 1834 mY -= lineBox.top - display.viewOffset;
1812 1835
1813 for (var i = 0; i < cm.options.gutters.length; ++i) { 1836 for (var i = 0; i < cm.options.gutters.length; ++i) {
1814 var g = display.gutters.childNodes[i]; 1837 var g = display.gutters.childNodes[i];
1815 if (g && getRect(g).right >= mX) { 1838 if (g && getRect(g).right >= mX) {
1816 var line = lineAtHeight(cm.doc, mY); 1839 var line = lineAtHeight(cm.doc, mY);
1817 var gutter = cm.options.gutters[i]; 1840 var gutter = cm.options.gutters[i];
1818 signalLater(cm, "gutterClick", cm, line, gutter, e); 1841 signalfn(cm, type, cm, line, gutter, e);
1819 break; 1842 return e_defaultPrevented(e);
1820 } 1843 }
1821 } 1844 }
1822 return true; 1845 }
1846
1847 function contextMenuInGutter(cm, e) {
1848 if (!hasHandler(cm, "gutterContextMenu")) return false;
1849 return gutterEvent(cm, e, "gutterContextMenu", false, signal);
1850 }
1851
1852 function clickInGutter(cm, e) {
1853 return gutterEvent(cm, e, "gutterClick", true, signalLater);
1823 } 1854 }
1824 1855
1825 // Kludge to work around strange IE behavior where it'll sometimes 1856 // Kludge to work around strange IE behavior where it'll sometimes
1826 // re-fire a series of drag-related events right after the drop (#1551) 1857 // re-fire a series of drag-related events right after the drop (#1551)
1827 var lastDrop = 0; 1858 var lastDrop = 0;
1828 1859
1829 function onDrop(e) { 1860 function onDrop(e) {
1830 var cm = this; 1861 var cm = this;
1831 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e) || (cm.options.onD ragEvent && cm.options.onDragEvent(cm, addStop(e)))) 1862 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e) || (cm.options.onD ragEvent && cm.options.onDragEvent(cm, addStop(e))))
1832 return; 1863 return;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1875 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e ); return; } 1906 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e ); return; }
1876 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; 1907 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
1877 1908
1878 var txt = cm.getSelection(); 1909 var txt = cm.getSelection();
1879 e.dataTransfer.setData("Text", txt); 1910 e.dataTransfer.setData("Text", txt);
1880 1911
1881 // Use dummy image instead of default browsers image. 1912 // Use dummy image instead of default browsers image.
1882 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. 1913 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
1883 if (e.dataTransfer.setDragImage && !safari) { 1914 if (e.dataTransfer.setDragImage && !safari) {
1884 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); 1915 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
1916 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAA AICTAEAOw==";
1885 if (opera) { 1917 if (opera) {
1886 img.width = img.height = 1; 1918 img.width = img.height = 1;
1887 cm.display.wrapper.appendChild(img); 1919 cm.display.wrapper.appendChild(img);
1888 // Force a relayout, or Opera won't use our image for some obscure reaso n 1920 // Force a relayout, or Opera won't use our image for some obscure reaso n
1889 img._top = img.offsetTop; 1921 img._top = img.offsetTop;
1890 } 1922 }
1891 e.dataTransfer.setDragImage(img, 0, 0); 1923 e.dataTransfer.setDragImage(img, 0, 0);
1892 if (opera) img.parentNode.removeChild(img); 1924 if (opera) img.parentNode.removeChild(img);
1893 } 1925 }
1894 } 1926 }
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
2073 restartBlink(cm); 2105 restartBlink(cm);
2074 signalLater(cm, "keyHandled", cm, "'" + ch + "'", e); 2106 signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
2075 } 2107 }
2076 return handled; 2108 return handled;
2077 } 2109 }
2078 2110
2079 var lastStoppedKey = null; 2111 var lastStoppedKey = null;
2080 function onKeyDown(e) { 2112 function onKeyDown(e) {
2081 var cm = this; 2113 var cm = this;
2082 if (!cm.state.focused) onFocus(cm); 2114 if (!cm.state.focused) onFocus(cm);
2083 if (ie && e.keyCode == 27) { e.returnValue = false; }
2084 if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent( cm, addStop(e))) return; 2115 if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent( cm, addStop(e))) return;
2116 if (ie && e.keyCode == 27) e.returnValue = false;
2085 var code = e.keyCode; 2117 var code = e.keyCode;
2086 // IE does strange things with escape. 2118 // IE does strange things with escape.
2087 cm.doc.sel.shift = code == 16 || e.shiftKey; 2119 cm.doc.sel.shift = code == 16 || e.shiftKey;
2088 // First give onKeyEvent option a chance to handle this. 2120 // First give onKeyEvent option a chance to handle this.
2089 var handled = handleKeyBinding(cm, e); 2121 var handled = handleKeyBinding(cm, e);
2090 if (opera) { 2122 if (opera) {
2091 lastStoppedKey = handled ? code : null; 2123 lastStoppedKey = handled ? code : null;
2092 // Opera has no cut event... we try to at least catch the key combo 2124 // Opera has no cut event... we try to at least catch the key combo
2093 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKe y)) 2125 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKe y))
2094 cm.replaceSelection(""); 2126 cm.replaceSelection("");
(...skipping 16 matching lines...) Expand all
2111 fastPoll(cm); 2143 fastPoll(cm);
2112 } 2144 }
2113 2145
2114 function onFocus(cm) { 2146 function onFocus(cm) {
2115 if (cm.options.readOnly == "nocursor") return; 2147 if (cm.options.readOnly == "nocursor") return;
2116 if (!cm.state.focused) { 2148 if (!cm.state.focused) {
2117 signal(cm, "focus", cm); 2149 signal(cm, "focus", cm);
2118 cm.state.focused = true; 2150 cm.state.focused = true;
2119 if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1) 2151 if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
2120 cm.display.wrapper.className += " CodeMirror-focused"; 2152 cm.display.wrapper.className += " CodeMirror-focused";
2121 resetInput(cm, true); 2153 if (!cm.curOp) {
2154 resetInput(cm, true);
2155 if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
2156 }
2122 } 2157 }
2123 slowPoll(cm); 2158 slowPoll(cm);
2124 restartBlink(cm); 2159 restartBlink(cm);
2125 } 2160 }
2126 function onBlur(cm) { 2161 function onBlur(cm) {
2127 if (cm.state.focused) { 2162 if (cm.state.focused) {
2128 signal(cm, "blur", cm); 2163 signal(cm, "blur", cm);
2129 cm.state.focused = false; 2164 cm.state.focused = false;
2130 cm.display.wrapper.className = cm.display.wrapper.className.replace(" Code Mirror-focused", ""); 2165 cm.display.wrapper.className = cm.display.wrapper.className.replace(" Code Mirror-focused", "");
2131 } 2166 }
2132 clearInterval(cm.display.blinker); 2167 clearInterval(cm.display.blinker);
2133 setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 15 0); 2168 setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 15 0);
2134 } 2169 }
2135 2170
2136 var detectingSelectAll; 2171 var detectingSelectAll;
2137 function onContextMenu(cm, e) { 2172 function onContextMenu(cm, e) {
2138 if (signalDOMEvent(cm, e, "contextmenu")) return; 2173 if (signalDOMEvent(cm, e, "contextmenu")) return;
2139 var display = cm.display, sel = cm.doc.sel; 2174 var display = cm.display, sel = cm.doc.sel;
2140 if (eventInWidget(display, e)) return; 2175 if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
2141 2176
2142 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; 2177 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
2143 if (!pos || opera) return; // Opera is difficult. 2178 if (!pos || opera) return; // Opera is difficult.
2144 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.t o)) 2179 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.t o))
2145 operation(cm, setSelection)(cm.doc, pos, pos); 2180 operation(cm, setSelection)(cm.doc, pos, pos);
2146 2181
2147 var oldCSS = display.input.style.cssText; 2182 var oldCSS = display.input.style.cssText;
2148 display.inputDiv.style.position = "absolute"; 2183 display.inputDiv.style.position = "absolute";
2149 display.input.style.cssText = "position: fixed; width: 30px; height: 30px; t op: " + (e.clientY - 5) + 2184 display.input.style.cssText = "position: fixed; width: 30px; height: 30px; t op: " + (e.clientY - 5) +
2150 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; ou tline: none;" + 2185 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; ou tline: none;" +
2151 "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opaci ty: .05; filter: alpha(opacity=5);"; 2186 "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opaci ty: .05; filter: alpha(opacity=5);";
2152 focusInput(cm); 2187 focusInput(cm);
2153 resetInput(cm, true); 2188 resetInput(cm, true);
2154 // Adds "Select all" to context menu in FF 2189 // Adds "Select all" to context menu in FF
2155 if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " "; 2190 if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " ";
2156 2191
2157 function prepareSelectAllHack() { 2192 function prepareSelectAllHack() {
2158 if (display.input.selectionStart != null) { 2193 if (display.input.selectionStart != null) {
2159 var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value); 2194 var extval = display.input.value = "\u200b" + (posEq(sel.from, sel.to) ? "" : display.input.value);
2160 display.prevInput = " "; 2195 display.prevInput = "\u200b";
2161 display.input.selectionStart = 1; display.input.selectionEnd = extval.le ngth; 2196 display.input.selectionStart = 1; display.input.selectionEnd = extval.le ngth;
2162 } 2197 }
2163 } 2198 }
2164 function rehide() { 2199 function rehide() {
2165 display.inputDiv.style.position = "relative"; 2200 display.inputDiv.style.position = "relative";
2166 display.input.style.cssText = oldCSS; 2201 display.input.style.cssText = oldCSS;
2167 if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = sc rollPos; 2202 if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = sc rollPos;
2168 slowPoll(cm); 2203 slowPoll(cm);
2169 2204
2170 // Try to detect the user choosing select-all 2205 // Try to detect the user choosing select-all
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
2506 // numbers before the update. 2541 // numbers before the update.
2507 function setSelection(doc, anchor, head, bias, checkAtomic) { 2542 function setSelection(doc, anchor, head, bias, checkAtomic) {
2508 if (!checkAtomic && hasHandler(doc, "beforeSelectionChange") || doc.cm && ha sHandler(doc.cm, "beforeSelectionChange")) { 2543 if (!checkAtomic && hasHandler(doc, "beforeSelectionChange") || doc.cm && ha sHandler(doc.cm, "beforeSelectionChange")) {
2509 var filtered = filterSelectionChange(doc, anchor, head); 2544 var filtered = filterSelectionChange(doc, anchor, head);
2510 head = filtered.head; 2545 head = filtered.head;
2511 anchor = filtered.anchor; 2546 anchor = filtered.anchor;
2512 } 2547 }
2513 2548
2514 var sel = doc.sel; 2549 var sel = doc.sel;
2515 sel.goalColumn = null; 2550 sel.goalColumn = null;
2551 if (bias == null) bias = posLess(head, sel.head) ? -1 : 1;
2516 // Skip over atomic spans. 2552 // Skip over atomic spans.
2517 if (checkAtomic || !posEq(anchor, sel.anchor)) 2553 if (checkAtomic || !posEq(anchor, sel.anchor))
2518 anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push"); 2554 anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push");
2519 if (checkAtomic || !posEq(head, sel.head)) 2555 if (checkAtomic || !posEq(head, sel.head))
2520 head = skipAtomic(doc, head, bias, checkAtomic != "push"); 2556 head = skipAtomic(doc, head, bias, checkAtomic != "push");
2521 2557
2522 if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return; 2558 if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return;
2523 2559
2524 sel.anchor = anchor; sel.head = head; 2560 sel.anchor = anchor; sel.head = head;
2525 var inv = posLess(head, anchor); 2561 var inv = posLess(head, anchor);
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after
3150 if (width != null) this.display.wrapper.style.width = interpret(width); 3186 if (width != null) this.display.wrapper.style.width = interpret(width);
3151 if (height != null) this.display.wrapper.style.height = interpret(height); 3187 if (height != null) this.display.wrapper.style.height = interpret(height);
3152 if (this.options.lineWrapping) 3188 if (this.options.lineWrapping)
3153 this.display.measureLineCache.length = this.display.measureLineCachePos = 0; 3189 this.display.measureLineCache.length = this.display.measureLineCachePos = 0;
3154 this.curOp.forceUpdate = true; 3190 this.curOp.forceUpdate = true;
3155 }), 3191 }),
3156 3192
3157 operation: function(f){return runInOp(this, f);}, 3193 operation: function(f){return runInOp(this, f);},
3158 3194
3159 refresh: operation(null, function() { 3195 refresh: operation(null, function() {
3196 var badHeight = this.display.cachedTextHeight == null;
3160 clearCaches(this); 3197 clearCaches(this);
3161 updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop); 3198 updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop);
3162 regChange(this); 3199 regChange(this);
3200 if (badHeight) estimateLineHeights(this);
3163 }), 3201 }),
3164 3202
3165 swapDoc: operation(null, function(doc) { 3203 swapDoc: operation(null, function(doc) {
3166 var old = this.doc; 3204 var old = this.doc;
3167 old.cm = null; 3205 old.cm = null;
3168 attachDoc(this, doc); 3206 attachDoc(this, doc);
3169 clearCaches(this); 3207 clearCaches(this);
3170 resetInput(this, true); 3208 resetInput(this, true);
3171 updateScrollPos(this, doc.scrollLeft, doc.scrollTop); 3209 updateScrollPos(this, doc.scrollLeft, doc.scrollTop);
3172 return old; 3210 return old;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
3253 option("cursorScrollMargin", 0); 3291 option("cursorScrollMargin", 0);
3254 option("cursorHeight", 1); 3292 option("cursorHeight", 1);
3255 option("workTime", 100); 3293 option("workTime", 100);
3256 option("workDelay", 100); 3294 option("workDelay", 100);
3257 option("flattenSpans", true); 3295 option("flattenSpans", true);
3258 option("pollInterval", 100); 3296 option("pollInterval", 100);
3259 option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); 3297 option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;});
3260 option("historyEventDelay", 500); 3298 option("historyEventDelay", 500);
3261 option("viewportMargin", 10, function(cm){cm.refresh();}, true); 3299 option("viewportMargin", 10, function(cm){cm.refresh();}, true);
3262 option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true); 3300 option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true);
3301 option("crudeMeasuringFrom", 10000);
3263 option("moveInputWithCursor", true, function(cm, val) { 3302 option("moveInputWithCursor", true, function(cm, val) {
3264 if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0 ; 3303 if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0 ;
3265 }); 3304 });
3266 3305
3267 option("tabindex", null, function(cm, val) { 3306 option("tabindex", null, function(cm, val) {
3268 cm.display.input.tabIndex = val || ""; 3307 cm.display.input.tabIndex = val || "";
3269 }); 3308 });
3270 option("autofocus", null); 3309 option("autofocus", null);
3271 3310
3272 // MODE DEFINITION AND QUERYING 3311 // MODE DEFINITION AND QUERYING
(...skipping 922 matching lines...) Expand 10 before | Expand all | Expand 10 after
4195 // classes. 4234 // classes.
4196 function runMode(cm, text, mode, state, f) { 4235 function runMode(cm, text, mode, state, f) {
4197 var flattenSpans = mode.flattenSpans; 4236 var flattenSpans = mode.flattenSpans;
4198 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; 4237 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
4199 var curStart = 0, curStyle = null; 4238 var curStart = 0, curStyle = null;
4200 var stream = new StringStream(text, cm.options.tabSize), style; 4239 var stream = new StringStream(text, cm.options.tabSize), style;
4201 if (text == "" && mode.blankLine) mode.blankLine(state); 4240 if (text == "" && mode.blankLine) mode.blankLine(state);
4202 while (!stream.eol()) { 4241 while (!stream.eol()) {
4203 if (stream.pos > cm.options.maxHighlightLength) { 4242 if (stream.pos > cm.options.maxHighlightLength) {
4204 flattenSpans = false; 4243 flattenSpans = false;
4205 // Webkit seems to refuse to render text nodes longer than 57444 charact ers 4244 stream.pos = text.length;
4206 stream.pos = Math.min(text.length, stream.start + 50000);
4207 style = null; 4245 style = null;
4208 } else { 4246 } else {
4209 style = mode.token(stream, state); 4247 style = mode.token(stream, state);
4210 } 4248 }
4211 if (!flattenSpans || curStyle != style) { 4249 if (!flattenSpans || curStyle != style) {
4212 if (curStart < stream.start) f(stream.start, curStyle); 4250 if (curStart < stream.start) f(stream.start, curStyle);
4213 curStart = stream.start; curStyle = style; 4251 curStart = stream.start; curStyle = style;
4214 } 4252 }
4215 stream.start = stream.pos; 4253 stream.start = stream.pos;
4216 } 4254 }
4217 if (curStart < stream.pos) f(stream.pos, curStyle); 4255 while (curStart < stream.pos) {
4256 // Webkit seems to refuse to render text nodes longer than 57444 character s
4257 var pos = Math.min(stream.pos, curStart + 50000);
4258 f(pos, curStyle);
4259 curStart = pos;
4260 }
4218 } 4261 }
4219 4262
4220 function highlightLine(cm, line, state) { 4263 function highlightLine(cm, line, state) {
4221 // A styles array always starts with a number identifying the 4264 // A styles array always starts with a number identifying the
4222 // mode/overlays that it is based on (for easy invalidation). 4265 // mode/overlays that it is based on (for easy invalidation).
4223 var st = [cm.state.modeGen]; 4266 var st = [cm.state.modeGen];
4224 // Compute the base array of styles 4267 // Compute the base array of styles
4225 runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end , style);}); 4268 runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end , style);});
4226 4269
4227 // Run overlays, adjust style array. 4270 // Run overlays, adjust style array.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
4265 var mode = cm.doc.mode; 4308 var mode = cm.doc.mode;
4266 var stream = new StringStream(line.text, cm.options.tabSize); 4309 var stream = new StringStream(line.text, cm.options.tabSize);
4267 if (line.text == "" && mode.blankLine) mode.blankLine(state); 4310 if (line.text == "" && mode.blankLine) mode.blankLine(state);
4268 while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { 4311 while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
4269 mode.token(stream, state); 4312 mode.token(stream, state);
4270 stream.start = stream.pos; 4313 stream.start = stream.pos;
4271 } 4314 }
4272 } 4315 }
4273 4316
4274 var styleToClassCache = {}; 4317 var styleToClassCache = {};
4275 function styleToClass(style) { 4318 function interpretTokenStyle(style, builder) {
4276 if (!style) return null; 4319 if (!style) return null;
4320 for (;;) {
4321 var lineClass = style.match(/(?:^|\s)line-(background-)?(\S+)/);
4322 if (!lineClass) break;
4323 style = style.slice(0, lineClass.index) + style.slice(lineClass.index + li neClass[0].length);
4324 var prop = lineClass[1] ? "bgClass" : "textClass";
4325 if (builder[prop] == null)
4326 builder[prop] = lineClass[2];
4327 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builde r[prop]))
4328 builder[prop] += " " + lineClass[2];
4329 }
4277 return styleToClassCache[style] || 4330 return styleToClassCache[style] ||
4278 (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-")); 4331 (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
4279 } 4332 }
4280 4333
4281 function lineContent(cm, realLine, measure, copyWidgets, from, to) { 4334 function buildLineContent(cm, realLine, measure, copyWidgets) {
4282 var merged, line = realLine, empty = true; 4335 var merged, line = realLine, empty = true;
4283 while (merged = collapsedSpanAtStart(line)) 4336 while (merged = collapsedSpanAtStart(line))
4284 line = getLine(cm.doc, merged.find().from.line); 4337 line = getLine(cm.doc, merged.find().from.line);
4285 4338
4286 var builder = {pre: elt("pre"), col: 0, pos: 0, 4339 var builder = {pre: elt("pre"), col: 0, pos: 0,
4287 measure: null, measuredSomething: false, cm: cm, from: from, to: to, 4340 measure: null, measuredSomething: false, cm: cm,
4288 copyWidgets: copyWidgets}; 4341 copyWidgets: copyWidgets};
4289 if (line.textClass) builder.pre.className = line.textClass;
4290 4342
4291 do { 4343 do {
4292 if (line.text) empty = false; 4344 if (line.text) empty = false;
4293 builder.measure = line == realLine && measure; 4345 builder.measure = line == realLine && measure;
4294 builder.pos = 0; 4346 builder.pos = 0;
4295 builder.addToken = builder.measure ? buildTokenMeasure : buildToken; 4347 builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
4296 if ((ie || webkit) && cm.getOption("lineWrapping")) 4348 if ((ie || webkit) && cm.getOption("lineWrapping"))
4297 builder.addToken = buildTokenSplitSpaces(builder.addToken); 4349 builder.addToken = buildTokenSplitSpaces(builder.addToken);
4298 var next = insertLineContent(line, builder, getLineStyles(cm, line)); 4350 var next = insertLineContent(line, builder, getLineStyles(cm, line));
4299 if (measure && line == realLine && !builder.measuredSomething) { 4351 if (measure && line == realLine && !builder.measuredSomething) {
(...skipping 16 matching lines...) Expand all
4316 var l = order.length - 1; 4368 var l = order.length - 1;
4317 if (order[l].from == order[l].to) --l; 4369 if (order[l].from == order[l].to) --l;
4318 var last = order[l], prev = order[l - 1]; 4370 var last = order[l], prev = order[l - 1];
4319 if (last.from + 1 == last.to && prev && last.level < prev.level) { 4371 if (last.from + 1 == last.to && prev && last.level < prev.level) {
4320 var span = measure[builder.pos - 1]; 4372 var span = measure[builder.pos - 1];
4321 if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElem ent(cm.display.measure), 4373 if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElem ent(cm.display.measure),
4322 span.nextSibling); 4374 span.nextSibling);
4323 } 4375 }
4324 } 4376 }
4325 4377
4378 var textClass = builder.textClass ? builder.textClass + " " + (realLine.text Class || "") : realLine.textClass;
4379 if (textClass) builder.pre.className = textClass;
4380
4326 signal(cm, "renderLine", cm, realLine, builder.pre); 4381 signal(cm, "renderLine", cm, realLine, builder.pre);
4327 return builder.pre; 4382 return builder;
4328 } 4383 }
4329 4384
4330 var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; 4385 var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g;
4331 function buildToken(builder, text, style, startStyle, endStyle, title) { 4386 function buildToken(builder, text, style, startStyle, endStyle, title) {
4332 if (!text) return; 4387 if (!text) return;
4333 if (!tokenSpecialChars.test(text)) { 4388 if (!tokenSpecialChars.test(text)) {
4334 builder.col += text.length; 4389 builder.col += text.length;
4335 var content = document.createTextNode(text); 4390 var content = document.createTextNode(text);
4336 } else { 4391 } else {
4337 var content = document.createDocumentFragment(), pos = 0; 4392 var content = document.createDocumentFragment(), pos = 0;
(...skipping 24 matching lines...) Expand all
4362 if (startStyle) fullStyle += startStyle; 4417 if (startStyle) fullStyle += startStyle;
4363 if (endStyle) fullStyle += endStyle; 4418 if (endStyle) fullStyle += endStyle;
4364 var token = elt("span", [content], fullStyle); 4419 var token = elt("span", [content], fullStyle);
4365 if (title) token.title = title; 4420 if (title) token.title = title;
4366 return builder.pre.appendChild(token); 4421 return builder.pre.appendChild(token);
4367 } 4422 }
4368 builder.pre.appendChild(content); 4423 builder.pre.appendChild(content);
4369 } 4424 }
4370 4425
4371 function buildTokenMeasure(builder, text, style, startStyle, endStyle) { 4426 function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
4372 //FIXME consider 2-byte chars
4373 if (builder.from || builder.to) {
4374 if (builder.from >= builder.pos + text.length) {
4375 buildToken(builder, text, style, startStyle, endStyle);
4376 builder.pos += text.length;
4377 return;
4378 }
4379 }
4380 var wrapping = builder.cm.options.lineWrapping; 4427 var wrapping = builder.cm.options.lineWrapping;
4381 for (var i = 0; i < text.length; ++i) { 4428 for (var i = 0; i < text.length; ++i) {
4382 var ch = text.charAt(i), start = i == 0; 4429 var ch = text.charAt(i), start = i == 0;
4383 if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { 4430 if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) {
4384 ch = text.slice(i, i + 2); 4431 ch = text.slice(i, i + 2);
4385 ++i; 4432 ++i;
4386 } else if (i && wrapping && spanAffectsWrapping(text, i)) { 4433 } else if (i && wrapping && spanAffectsWrapping(text, i)) {
4387 builder.pre.appendChild(elt("wbr")); 4434 builder.pre.appendChild(elt("wbr"));
4388 } 4435 }
4389 var old = builder.measure[builder.pos]; 4436 var old = builder.measure[builder.pos];
(...skipping 26 matching lines...) Expand all
4416 4463
4417 function buildCollapsedSpan(builder, size, marker, ignoreWidget) { 4464 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
4418 var widget = !ignoreWidget && marker.replacedWith; 4465 var widget = !ignoreWidget && marker.replacedWith;
4419 if (widget) { 4466 if (widget) {
4420 if (builder.copyWidgets) widget = widget.cloneNode(true); 4467 if (builder.copyWidgets) widget = widget.cloneNode(true);
4421 builder.pre.appendChild(widget); 4468 builder.pre.appendChild(widget);
4422 if (builder.measure) { 4469 if (builder.measure) {
4423 if (size) { 4470 if (size) {
4424 builder.measure[builder.pos] = widget; 4471 builder.measure[builder.pos] = widget;
4425 } else { 4472 } else {
4426 var elt = builder.measure[builder.pos] = zeroWidthElement(builder.cm.d isplay.measure); 4473 var elt = zeroWidthElement(builder.cm.display.measure);
4427 if (marker.type != "bookmark" || marker.insertLeft) 4474 if (marker.type == "bookmark" && !marker.insertLeft)
4428 builder.pre.insertBefore(elt, widget); 4475 builder.measure[builder.pos] = builder.pre.appendChild(elt);
4476 else if (builder.measure[builder.pos])
4477 return;
4429 else 4478 else
4430 builder.pre.appendChild(elt); 4479 builder.measure[builder.pos] = builder.pre.insertBefore(elt, widget) ;
4431 } 4480 }
4432 builder.measuredSomething = true; 4481 builder.measuredSomething = true;
4433 } 4482 }
4434 } 4483 }
4435 builder.pos += size; 4484 builder.pos += size;
4436 } 4485 }
4437 4486
4438 // Outputs a number of spans to make up a line, taking highlighting 4487 // Outputs a number of spans to make up a line, taking highlighting
4439 // and marked text into account. 4488 // and marked text into account.
4440 function insertLineContent(line, builder, styles) { 4489 function insertLineContent(line, builder, styles) {
4441 var spans = line.markedSpans, allText = line.text, at = 0; 4490 var spans = line.markedSpans, allText = line.text, at = 0;
4442 if (!spans) { 4491 if (!spans) {
4443 if (builder.to || builder.from) { 4492 for (var i = 1; i < styles.length; i+=2)
4444 for (var i = 1; i < styles.length && (!builder.to || builder.pos < build er.to); i+=2) { 4493 builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTo kenStyle(styles[i+1], builder));
4445 var text = allText.slice(at, at = styles[i]);
4446 var textLength = text.length;
4447 var resolvedStyles = styleToClass(styles[i+1]);
4448 if (builder.pos + textLength <= builder.from) {
4449 builder.addToken(builder, text, resolvedStyles);
4450 continue;
4451 }
4452 // if we are not inside, but will get over it
4453 if (builder.pos < builder.from && builder.pos + textLength > builder.f rom) {
4454 var overlap = builder.from - builder.pos;
4455 builder.addToken(builder, text.substring(0, overlap), resolvedStyles );
4456 text = text.substring(overlap);
4457 }
4458 builder.addToken(builder, text.substr(0, Math.min(builder.to - builder .from, text.length)), resolvedStyles);
4459 }
4460 } else {
4461 for (var i = 1; i < styles.length; i+=2)
4462 builder.addToken(builder, allText.slice(at, at = styles[i]), styleToCl ass(styles[i+1]));
4463 }
4464 return; 4494 return;
4465 } 4495 }
4466 4496
4467 var len = allText.length, pos = 0, i = 1, text = "", style; 4497 var len = allText.length, pos = 0, i = 1, text = "", style;
4468 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapse d; 4498 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapse d;
4469 for (;;) { 4499 for (;;) {
4470 if (nextChange == pos) { // Update current marker set 4500 if (nextChange == pos) { // Update current marker set
4471 spanStyle = spanEndStyle = spanStartStyle = title = ""; 4501 spanStyle = spanEndStyle = spanStartStyle = title = "";
4472 collapsed = null; nextChange = Infinity; 4502 collapsed = null; nextChange = Infinity;
4473 var foundBookmarks = []; 4503 var foundBookmarks = [];
(...skipping 23 matching lines...) Expand all
4497 if (pos >= len) break; 4527 if (pos >= len) break;
4498 4528
4499 var upto = Math.min(len, nextChange); 4529 var upto = Math.min(len, nextChange);
4500 while (true) { 4530 while (true) {
4501 if (text) { 4531 if (text) {
4502 var end = pos + text.length; 4532 var end = pos + text.length;
4503 if (!collapsed) { 4533 if (!collapsed) {
4504 var tokenText = end > upto ? text.slice(0, upto - pos) : text; 4534 var tokenText = end > upto ? text.slice(0, upto - pos) : text;
4505 builder.addToken(builder, tokenText, style ? style + spanStyle : spa nStyle, 4535 builder.addToken(builder, tokenText, style ? style + spanStyle : spa nStyle,
4506 spanStartStyle, pos + tokenText.length == nextChang e ? spanEndStyle : "", title); 4536 spanStartStyle, pos + tokenText.length == nextChang e ? spanEndStyle : "", title);
4507 if (builder.to && builder.pos >= builder.to)
4508 return;
4509 } 4537 }
4510 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} 4538 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
4511 pos = end; 4539 pos = end;
4512 spanStartStyle = ""; 4540 spanStartStyle = "";
4513 } 4541 }
4514 text = allText.slice(at, at = styles[i++]); 4542 text = allText.slice(at, at = styles[i++]);
4515 style = styleToClass(styles[i++]); 4543 style = interpretTokenStyle(styles[i++], builder);
4516 } 4544 }
4517 } 4545 }
4518 } 4546 }
4519 4547
4520 // DOCUMENT DATA STRUCTURE 4548 // DOCUMENT DATA STRUCTURE
4521 4549
4522 function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) { 4550 function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) {
4523 function spansFor(n) {return markedSpans ? markedSpans[n] : null;} 4551 function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
4524 function update(line, text, spans) { 4552 function update(line, text, spans) {
4525 updateLine(line, text, spans, estimateHeight); 4553 updateLine(line, text, spans, estimateHeight);
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
4783 else pos = sel.from; 4811 else pos = sel.from;
4784 return copyPos(pos); 4812 return copyPos(pos);
4785 }, 4813 },
4786 somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor) ;}, 4814 somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor) ;},
4787 4815
4788 setCursor: docOperation(function(line, ch, extend) { 4816 setCursor: docOperation(function(line, ch, extend) {
4789 var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : lin e); 4817 var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : lin e);
4790 if (extend) extendSelection(this, pos); 4818 if (extend) extendSelection(this, pos);
4791 else setSelection(this, pos, pos); 4819 else setSelection(this, pos, pos);
4792 }), 4820 }),
4793 setSelection: docOperation(function(anchor, head) { 4821 setSelection: docOperation(function(anchor, head, bias) {
4794 setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor)); 4822 setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), b ias);
4795 }), 4823 }),
4796 extendSelection: docOperation(function(from, to) { 4824 extendSelection: docOperation(function(from, to, bias) {
4797 extendSelection(this, clipPos(this, from), to && clipPos(this, to)); 4825 extendSelection(this, clipPos(this, from), to && clipPos(this, to), bias);
4798 }), 4826 }),
4799 4827
4800 getSelection: function(lineSep) {return this.getRange(this.sel.from, this.se l.to, lineSep);}, 4828 getSelection: function(lineSep) {return this.getRange(this.sel.from, this.se l.to, lineSep);},
4801 replaceSelection: function(code, collapse, origin) { 4829 replaceSelection: function(code, collapse, origin) {
4802 makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(c ode), origin: origin}, collapse || "around"); 4830 makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(c ode), origin: origin}, collapse || "around");
4803 }, 4831 },
4804 undo: docOperation(function() {makeChangeFromHistory(this, "undo");}), 4832 undo: docOperation(function() {makeChangeFromHistory(this, "undo");}),
4805 redo: docOperation(function() {makeChangeFromHistory(this, "redo");}), 4833 redo: docOperation(function() {makeChangeFromHistory(this, "redo");}),
4806 4834
4807 setExtending: function(val) {this.sel.extend = val;}, 4835 setExtending: function(val) {this.sel.extend = val;},
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after
5473 // various browsers. 5501 // various browsers.
5474 function spanAffectsWrapping() { return false; } 5502 function spanAffectsWrapping() { return false; }
5475 if (gecko) // Only for "$'" 5503 if (gecko) // Only for "$'"
5476 spanAffectsWrapping = function(str, i) { 5504 spanAffectsWrapping = function(str, i) {
5477 return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39; 5505 return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39;
5478 }; 5506 };
5479 else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) 5507 else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent))
5480 spanAffectsWrapping = function(str, i) { 5508 spanAffectsWrapping = function(str, i) {
5481 return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1 )); 5509 return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1 ));
5482 }; 5510 };
5483 else if (webkit && !/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent )) 5511 else if (webkit && /Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent) )
5512 spanAffectsWrapping = function(str, i) {
5513 var code = str.charCodeAt(i - 1);
5514 return code >= 8208 && code <= 8212;
5515 };
5516 else if (webkit)
5484 spanAffectsWrapping = function(str, i) { 5517 spanAffectsWrapping = function(str, i) {
5485 if (i > 1 && str.charCodeAt(i - 1) == 45) { 5518 if (i > 1 && str.charCodeAt(i - 1) == 45) {
5486 if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) retu rn true; 5519 if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) retu rn true;
5487 if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.cha rAt(i))) return false; 5520 if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.cha rAt(i))) return false;
5488 } 5521 }
5489 return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~` @#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1)); 5522 return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~` @#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1));
5490 }; 5523 };
5491 5524
5492 var knownScrollbarWidth; 5525 var knownScrollbarWidth;
5493 function scrollbarWidth(measure) { 5526 function scrollbarWidth(measure) {
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
5835 } 5868 }
5836 if (order[0].level != lst(order).level) 5869 if (order[0].level != lst(order).level)
5837 order.push({from: len, to: len, level: order[0].level}); 5870 order.push({from: len, to: len, level: order[0].level});
5838 5871
5839 return order; 5872 return order;
5840 }; 5873 };
5841 })(); 5874 })();
5842 5875
5843 // THE END 5876 // THE END
5844 5877
5845 CodeMirror.version = "3.15.1"; 5878 CodeMirror.version = "3.16.1";
5846 5879
5847 return CodeMirror; 5880 return CodeMirror;
5848 })(); 5881 })();
OLDNEW
« no previous file with comments | « Source/devtools/front_end/cm/codemirror.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698