resin 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/amber/css/amber-normalize.css +73 -73
- data/amber/css/amber-normalize.less +1 -1
- data/amber/css/amber.css +106 -106
- data/amber/css/helios.css +242 -0
- data/amber/images/hsplitter.png +0 -0
- data/amber/images/vsplitter.png +0 -0
- data/amber/js/Benchfib.deploy.js +116 -38
- data/amber/js/Benchfib.js +120 -42
- data/amber/js/Canvas.deploy.js +674 -403
- data/amber/js/Canvas.js +682 -411
- data/amber/js/Compiler-AST.deploy.js +1150 -0
- data/amber/js/Compiler-AST.js +1591 -0
- data/amber/js/Compiler-Core.deploy.js +1562 -0
- data/amber/js/Compiler-Core.js +1972 -0
- data/amber/js/Compiler-Exceptions.deploy.js +114 -0
- data/amber/js/Compiler-Exceptions.js +161 -0
- data/amber/js/Compiler-IR.deploy.js +2326 -0
- data/amber/js/Compiler-IR.js +3146 -0
- data/amber/js/Compiler-Inlining.deploy.js +1147 -0
- data/amber/js/Compiler-Inlining.js +1514 -0
- data/amber/js/Compiler-Semantic.deploy.js +1207 -0
- data/amber/js/Compiler-Semantic.js +1628 -0
- data/amber/js/Compiler-Tests.deploy.js +646 -60
- data/amber/js/Compiler-Tests.js +843 -82
- data/amber/js/Compiler.deploy.js +1097 -159
- data/amber/js/Compiler.js +1414 -161
- data/amber/js/Examples.deploy.js +31 -15
- data/amber/js/Examples.js +33 -17
- data/amber/js/Helios-Announcements.deploy.js +127 -0
- data/amber/js/Helios-Announcements.js +157 -0
- data/amber/js/Helios-Browser.deploy.js +1473 -0
- data/amber/js/Helios-Browser.js +1953 -0
- data/amber/js/Helios-Commands.deploy.js +403 -0
- data/amber/js/Helios-Commands.js +563 -0
- data/amber/js/Helios-Core.deploy.js +1070 -0
- data/amber/js/Helios-Core.js +1445 -0
- data/amber/js/Helios-Environments.deploy.js +132 -0
- data/amber/js/Helios-Environments.js +179 -0
- data/amber/js/Helios-Inspector.deploy.js +855 -0
- data/amber/js/Helios-Inspector.js +1155 -0
- data/amber/js/Helios-KeyBindings.deploy.js +753 -0
- data/amber/js/Helios-KeyBindings.js +1023 -0
- data/amber/js/Helios-Layout.deploy.js +383 -0
- data/amber/js/Helios-Layout.js +523 -0
- data/amber/js/Helios-Workspace.deploy.js +799 -0
- data/amber/js/Helios-Workspace.js +1074 -0
- data/amber/js/IDE.deploy.js +2541 -1490
- data/amber/js/IDE.js +2721 -1660
- data/amber/js/Importer-Exporter.deploy.js +671 -0
- data/amber/js/Importer-Exporter.js +816 -0
- data/amber/js/Kernel-Announcements.deploy.js +137 -20
- data/amber/js/Kernel-Announcements.js +176 -22
- data/amber/js/Kernel-Classes.deploy.js +555 -168
- data/amber/js/Kernel-Classes.js +662 -205
- data/amber/js/Kernel-Collections.deploy.js +1403 -618
- data/amber/js/Kernel-Collections.js +1545 -690
- data/amber/js/Kernel-Exceptions.deploy.js +109 -45
- data/amber/js/Kernel-Exceptions.js +123 -49
- data/amber/js/Kernel-Methods.deploy.js +196 -81
- data/amber/js/Kernel-Methods.js +214 -89
- data/amber/js/Kernel-Objects.deploy.js +1542 -1117
- data/amber/js/Kernel-Objects.js +1593 -1148
- data/amber/js/Kernel-Tests.deploy.js +1725 -772
- data/amber/js/Kernel-Tests.js +2301 -1123
- data/amber/js/Kernel-Transcript.deploy.js +23 -25
- data/amber/js/Kernel-Transcript.js +24 -26
- data/amber/js/SUnit.deploy.js +204 -131
- data/amber/js/SUnit.js +222 -139
- data/amber/js/Spaces.deploy.js +240 -0
- data/amber/js/Spaces.js +326 -0
- data/amber/js/amber.js +26 -7
- data/amber/js/boot.js +65 -47
- data/amber/js/init.js +1 -1
- data/amber/js/lib/CodeMirror/amber.css +21 -21
- data/amber/js/lib/CodeMirror/codemirror.css +119 -13
- data/amber/js/lib/CodeMirror/codemirror.js +2219 -1220
- data/amber/js/lib/CodeMirror/smalltalk.js +134 -129
- data/amber/js/lib/bootstrap/css/bootstrap.css +5837 -0
- data/amber/js/lib/bootstrap/css/bootstrap.min.css +841 -0
- data/amber/js/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/amber/js/lib/bootstrap/img/glyphicons-halflings.png +0 -0
- data/amber/js/lib/bootstrap/js/bootstrap.js +2038 -0
- data/amber/js/lib/bootstrap/js/bootstrap.min.js +7 -0
- data/amber/js/lib/jQuery/jquery-1.8.2.min.js +2 -0
- data/amber/js/lib/jQuery/jquery-ui-1.8.24.custom.min.js +125 -0
- data/amber/st/Compiler-AST.st +505 -0
- data/amber/st/Compiler-Core.st +835 -0
- data/amber/st/Compiler-Exceptions.st +87 -0
- data/amber/st/Compiler-IR.st +1097 -0
- data/amber/st/Compiler-Inlining.st +650 -0
- data/amber/st/Compiler-Semantic.st +558 -0
- data/amber/st/Compiler-Tests.st +285 -381
- data/amber/st/Compiler.st +725 -2
- data/amber/st/Helios-Announcements.st +104 -0
- data/amber/st/Helios-Browser.st +708 -0
- data/amber/st/Helios-Commands.st +223 -0
- data/amber/st/Helios-Core.st +532 -0
- data/amber/st/Helios-Environments.st +98 -0
- data/amber/st/Helios-Inspector.st +367 -0
- data/amber/st/Helios-KeyBindings.st +337 -0
- data/amber/st/Helios-Layout.st +199 -0
- data/amber/st/Helios-Workspace.st +367 -0
- data/amber/st/IDE.st +75 -53
- data/amber/st/Importer-Exporter.st +386 -0
- data/amber/st/Kernel-Announcements.st +92 -0
- data/amber/st/Kernel-Classes.st +137 -15
- data/amber/st/Kernel-Collections.st +137 -47
- data/amber/st/Kernel-Exceptions.st +14 -0
- data/amber/st/Kernel-Methods.st +9 -1
- data/amber/st/Kernel-Objects.st +29 -5
- data/amber/st/Kernel-Tests.st +545 -199
- data/amber/st/SUnit.st +10 -0
- data/amber/st/Spaces.st +142 -0
- data/lib/resin/app.rb +1 -1
- metadata +86 -31
- data/amber/js/lib/jQuery/jquery-1.4.4.min.js +0 -167
- data/amber/js/lib/jQuery/jquery-1.6.4.min.js +0 -4
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
// CodeMirror version 2.34
|
|
2
|
+
|
|
1
3
|
// All functions that need access to the editor's state live inside
|
|
2
4
|
// the CodeMirror function. Below that, at the bottom of the file,
|
|
3
5
|
// some utilities are defined.
|
|
4
6
|
|
|
5
7
|
// CodeMirror is the only global var we claim
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
window.CodeMirror = (function() {
|
|
9
|
+
"use strict";
|
|
10
|
+
// This is the function that produces an editor instance. Its
|
|
8
11
|
// closure is used to store the editor state.
|
|
9
12
|
function CodeMirror(place, givenOptions) {
|
|
10
13
|
// Determine effective options based on given values and defaults.
|
|
@@ -13,231 +16,426 @@ var CodeMirror = (function() {
|
|
|
13
16
|
if (defaults.hasOwnProperty(opt))
|
|
14
17
|
options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
|
|
15
18
|
|
|
16
|
-
var
|
|
19
|
+
var input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em");
|
|
20
|
+
input.setAttribute("wrap", "off"); input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off");
|
|
21
|
+
// Wraps and hides input textarea
|
|
22
|
+
var inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
|
|
23
|
+
// The empty scrollbar content, used solely for managing the scrollbar thumb.
|
|
24
|
+
var scrollbarInner = elt("div", null, "CodeMirror-scrollbar-inner");
|
|
25
|
+
// The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
|
|
26
|
+
var scrollbar = elt("div", [scrollbarInner], "CodeMirror-scrollbar");
|
|
27
|
+
// DIVs containing the selection and the actual code
|
|
28
|
+
var lineDiv = elt("div"), selectionDiv = elt("div", null, null, "position: relative; z-index: -1");
|
|
29
|
+
// Blinky cursor, and element used to ensure cursor fits at the end of a line
|
|
30
|
+
var cursor = elt("pre", "\u00a0", "CodeMirror-cursor"), widthForcer = elt("pre", "\u00a0", "CodeMirror-cursor", "visibility: hidden");
|
|
31
|
+
// Used to measure text size
|
|
32
|
+
var measure = elt("div", null, null, "position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden;");
|
|
33
|
+
var lineSpace = elt("div", [measure, cursor, widthForcer, selectionDiv, lineDiv], null, "position: relative; z-index: 0");
|
|
34
|
+
var gutterText = elt("div", null, "CodeMirror-gutter-text"), gutter = elt("div", [gutterText], "CodeMirror-gutter");
|
|
35
|
+
// Moved around its parent to cover visible view
|
|
36
|
+
var mover = elt("div", [gutter, elt("div", [lineSpace], "CodeMirror-lines")], null, "position: relative");
|
|
37
|
+
// Set to the height of the text, causes scrolling
|
|
38
|
+
var sizer = elt("div", [mover], null, "position: relative");
|
|
39
|
+
// Provides scrolling
|
|
40
|
+
var scroller = elt("div", [sizer], "CodeMirror-scroll");
|
|
41
|
+
scroller.setAttribute("tabIndex", "-1");
|
|
17
42
|
// The element in which the editor lives.
|
|
18
|
-
var wrapper =
|
|
19
|
-
wrapper.className = "CodeMirror";
|
|
20
|
-
// This mess creates the base DOM structure for the editor.
|
|
21
|
-
wrapper.innerHTML =
|
|
22
|
-
'<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
|
|
23
|
-
'<textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div>' +
|
|
24
|
-
'<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
|
|
25
|
-
'<div style="position: relative">' + // Set to the height of the text, causes scrolling
|
|
26
|
-
'<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
|
|
27
|
-
'<div style="position: relative">' + // Moved around its parent to cover visible view
|
|
28
|
-
'<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
|
|
29
|
-
// Provides positioning relative to (visible) text origin
|
|
30
|
-
'<div class="CodeMirror-lines"><div style="position: relative">' +
|
|
31
|
-
'<pre class="CodeMirror-cursor"> </pre>' + // Absolutely positioned blinky cursor
|
|
32
|
-
'<div></div>' + // This DIV contains the actual code
|
|
33
|
-
'</div></div></div></div></div>';
|
|
43
|
+
var wrapper = elt("div", [inputDiv, scrollbar, scroller], "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : ""));
|
|
34
44
|
if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (options.
|
|
45
|
+
|
|
46
|
+
themeChanged(); keyMapChanged();
|
|
47
|
+
// Needed to hide big blue blinking cursor on Mobile Safari
|
|
48
|
+
if (ios) input.style.width = "0px";
|
|
49
|
+
if (!webkit) scroller.draggable = true;
|
|
50
|
+
lineSpace.style.outline = "none";
|
|
51
|
+
if (options.tabindex != null) input.tabIndex = options.tabindex;
|
|
52
|
+
if (options.autofocus) focusInput();
|
|
43
53
|
if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
|
|
54
|
+
// Needed to handle Tab key in KHTML
|
|
55
|
+
if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
|
|
56
|
+
|
|
57
|
+
// Check for OS X >= 10.7. This has transparent scrollbars, so the
|
|
58
|
+
// overlaying of one scrollbar with another won't work. This is a
|
|
59
|
+
// temporary hack to simply turn off the overlay scrollbar. See
|
|
60
|
+
// issue #727.
|
|
61
|
+
if (mac_geLion) { scrollbar.style.zIndex = -2; scrollbar.style.visibility = "hidden"; }
|
|
62
|
+
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
|
|
63
|
+
else if (ie_lt8) scrollbar.style.minWidth = "18px";
|
|
44
64
|
|
|
45
65
|
// Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
|
|
46
66
|
var poll = new Delayed(), highlight = new Delayed(), blinker;
|
|
47
67
|
|
|
48
|
-
// mode holds a mode API object.
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
var mode, lines = [new Line("")], work, history = new History(), focused;
|
|
68
|
+
// mode holds a mode API object. doc is the tree of Line objects,
|
|
69
|
+
// frontier is the point up to which the content has been parsed,
|
|
70
|
+
// and history the undo history (instance of History constructor).
|
|
71
|
+
var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), frontier = 0, focused;
|
|
53
72
|
loadMode();
|
|
54
73
|
// The selection. These are always maintained to point at valid
|
|
55
74
|
// positions. Inverted is used to remember that the user is
|
|
56
75
|
// selecting bottom-to-top.
|
|
57
76
|
var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
|
|
58
77
|
// Selection-related flags. shiftSelecting obviously tracks
|
|
59
|
-
// whether the user is holding shift.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
var shiftSelecting, reducedSelection, lastDoubleClick;
|
|
78
|
+
// whether the user is holding shift.
|
|
79
|
+
var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, draggingText,
|
|
80
|
+
overwrite = false, suppressEdits = false;
|
|
63
81
|
// Variables used by startOperation/endOperation to track what
|
|
64
82
|
// happened during the operation.
|
|
65
|
-
var updateInput, changes, textChanged, selectionChanged,
|
|
83
|
+
var updateInput, userSelChange, changes, textChanged, selectionChanged,
|
|
84
|
+
gutterDirty, callbacks;
|
|
66
85
|
// Current visible range (may be bigger than the view window).
|
|
67
|
-
var
|
|
68
|
-
//
|
|
69
|
-
// textarea, to help figure out whether something changed.
|
|
70
|
-
// bracketHighlighted is used to remember that a backet has been
|
|
86
|
+
var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
|
|
87
|
+
// bracketHighlighted is used to remember that a bracket has been
|
|
71
88
|
// marked.
|
|
72
|
-
var
|
|
89
|
+
var bracketHighlighted;
|
|
73
90
|
// Tracks the maximum line length so that the horizontal scrollbar
|
|
74
91
|
// can be kept static when scrolling.
|
|
75
|
-
var maxLine =
|
|
92
|
+
var maxLine = getLine(0), updateMaxLine = false, maxLineChanged = true;
|
|
93
|
+
var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
|
|
94
|
+
var goalColumn = null;
|
|
76
95
|
|
|
77
96
|
// Initialize the content.
|
|
78
97
|
operation(function(){setValue(options.value || ""); updateInput = false;})();
|
|
98
|
+
var history = new History();
|
|
79
99
|
|
|
80
100
|
// Register our event handlers.
|
|
81
101
|
connect(scroller, "mousedown", operation(onMouseDown));
|
|
102
|
+
connect(scroller, "dblclick", operation(onDoubleClick));
|
|
103
|
+
connect(lineSpace, "selectstart", e_preventDefault);
|
|
82
104
|
// Gecko browsers fire contextmenu *after* opening the menu, at
|
|
83
105
|
// which point we can't mess with it anymore. Context menu is
|
|
84
106
|
// handled in onMouseDown for Gecko.
|
|
85
107
|
if (!gecko) connect(scroller, "contextmenu", onContextMenu);
|
|
86
|
-
connect(
|
|
87
|
-
connect(
|
|
88
|
-
connect(
|
|
108
|
+
connect(scroller, "scroll", onScrollMain);
|
|
109
|
+
connect(scrollbar, "scroll", onScrollBar);
|
|
110
|
+
connect(scrollbar, "mousedown", function() {if (focused) setTimeout(focusInput, 0);});
|
|
111
|
+
var resizeHandler = connect(window, "resize", function() {
|
|
112
|
+
if (wrapper.parentNode) updateDisplay(true);
|
|
113
|
+
else resizeHandler();
|
|
114
|
+
}, true);
|
|
89
115
|
connect(input, "keyup", operation(onKeyUp));
|
|
116
|
+
connect(input, "input", fastPoll);
|
|
90
117
|
connect(input, "keydown", operation(onKeyDown));
|
|
91
118
|
connect(input, "keypress", operation(onKeyPress));
|
|
92
119
|
connect(input, "focus", onFocus);
|
|
93
120
|
connect(input, "blur", onBlur);
|
|
94
121
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
122
|
+
function drag_(e) {
|
|
123
|
+
if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
|
|
124
|
+
e_stop(e);
|
|
125
|
+
}
|
|
126
|
+
if (options.dragDrop) {
|
|
127
|
+
connect(scroller, "dragstart", onDragStart);
|
|
128
|
+
connect(scroller, "dragenter", drag_);
|
|
129
|
+
connect(scroller, "dragover", drag_);
|
|
130
|
+
connect(scroller, "drop", operation(onDrop));
|
|
131
|
+
}
|
|
98
132
|
connect(scroller, "paste", function(){focusInput(); fastPoll();});
|
|
99
|
-
connect(input, "paste",
|
|
100
|
-
connect(input, "cut", function(){
|
|
101
|
-
|
|
102
|
-
|
|
133
|
+
connect(input, "paste", fastPoll);
|
|
134
|
+
connect(input, "cut", operation(function(){
|
|
135
|
+
if (!options.readOnly) replaceSelection("");
|
|
136
|
+
}));
|
|
137
|
+
|
|
138
|
+
// Needed to handle Tab key in KHTML
|
|
139
|
+
if (khtml) connect(sizer, "mouseup", function() {
|
|
140
|
+
if (document.activeElement == input) input.blur();
|
|
141
|
+
focusInput();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// IE throws unspecified error in certain cases, when
|
|
103
145
|
// trying to access activeElement before onload
|
|
104
|
-
var hasFocus; try { hasFocus = (
|
|
105
|
-
if (hasFocus) setTimeout(onFocus, 20);
|
|
146
|
+
var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { }
|
|
147
|
+
if (hasFocus || options.autofocus) setTimeout(onFocus, 20);
|
|
106
148
|
else onBlur();
|
|
107
149
|
|
|
108
|
-
function isLine(l) {return l >= 0 && l <
|
|
150
|
+
function isLine(l) {return l >= 0 && l < doc.size;}
|
|
109
151
|
// The instance object that we'll return. Mostly calls out to
|
|
110
152
|
// local functions in the CodeMirror function. Some do some extra
|
|
111
153
|
// range checking and/or clipping. operation is used to wrap the
|
|
112
154
|
// call so that changes it makes are tracked, and the display is
|
|
113
155
|
// updated afterwards.
|
|
114
|
-
var instance = {
|
|
156
|
+
var instance = wrapper.CodeMirror = {
|
|
115
157
|
getValue: getValue,
|
|
116
158
|
setValue: operation(setValue),
|
|
117
159
|
getSelection: getSelection,
|
|
118
160
|
replaceSelection: operation(replaceSelection),
|
|
119
|
-
focus: function(){focusInput(); onFocus(); fastPoll();},
|
|
161
|
+
focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
|
|
120
162
|
setOption: function(option, value) {
|
|
163
|
+
var oldVal = options[option];
|
|
121
164
|
options[option] = value;
|
|
122
|
-
if (option == "
|
|
123
|
-
else if (option == "
|
|
124
|
-
else if (option == "readOnly" && value
|
|
125
|
-
else if (option == "theme")
|
|
165
|
+
if (option == "mode" || option == "indentUnit") loadMode();
|
|
166
|
+
else if (option == "readOnly" && value == "nocursor") {onBlur(); input.blur();}
|
|
167
|
+
else if (option == "readOnly" && !value) {resetInput(true);}
|
|
168
|
+
else if (option == "theme") themeChanged();
|
|
169
|
+
else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
|
|
170
|
+
else if (option == "tabSize") updateDisplay(true);
|
|
171
|
+
else if (option == "keyMap") keyMapChanged();
|
|
172
|
+
if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" ||
|
|
173
|
+
option == "theme" || option == "lineNumberFormatter") {
|
|
174
|
+
gutterChanged();
|
|
175
|
+
updateDisplay(true);
|
|
176
|
+
}
|
|
126
177
|
},
|
|
127
178
|
getOption: function(option) {return options[option];},
|
|
179
|
+
getMode: function() {return mode;},
|
|
128
180
|
undo: operation(undo),
|
|
129
181
|
redo: operation(redo),
|
|
130
|
-
indentLine: operation(function(n) {
|
|
182
|
+
indentLine: operation(function(n, dir) {
|
|
183
|
+
if (typeof dir != "string") {
|
|
184
|
+
if (dir == null) dir = options.smartIndent ? "smart" : "prev";
|
|
185
|
+
else dir = dir ? "add" : "subtract";
|
|
186
|
+
}
|
|
187
|
+
if (isLine(n)) indentLine(n, dir);
|
|
188
|
+
}),
|
|
189
|
+
indentSelection: operation(indentSelected),
|
|
131
190
|
historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
|
|
191
|
+
clearHistory: function() {history = new History();},
|
|
192
|
+
setHistory: function(histData) {
|
|
193
|
+
history = new History();
|
|
194
|
+
history.done = histData.done;
|
|
195
|
+
history.undone = histData.undone;
|
|
196
|
+
},
|
|
197
|
+
getHistory: function() {
|
|
198
|
+
function cp(arr) {
|
|
199
|
+
for (var i = 0, nw = [], nwelt; i < arr.length; ++i) {
|
|
200
|
+
nw.push(nwelt = []);
|
|
201
|
+
for (var j = 0, elt = arr[i]; j < elt.length; ++j) {
|
|
202
|
+
var old = [], cur = elt[j];
|
|
203
|
+
nwelt.push({start: cur.start, added: cur.added, old: old});
|
|
204
|
+
for (var k = 0; k < cur.old.length; ++k) old.push(hlText(cur.old[k]));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return nw;
|
|
208
|
+
}
|
|
209
|
+
return {done: cp(history.done), undone: cp(history.undone)};
|
|
210
|
+
},
|
|
132
211
|
matchBrackets: operation(function(){matchBrackets(true);}),
|
|
133
|
-
getTokenAt: function(pos) {
|
|
212
|
+
getTokenAt: operation(function(pos) {
|
|
134
213
|
pos = clipPos(pos);
|
|
135
|
-
return
|
|
136
|
-
},
|
|
214
|
+
return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), options.tabSize, pos.ch);
|
|
215
|
+
}),
|
|
137
216
|
getStateAfter: function(line) {
|
|
138
|
-
line = clipLine(line == null ?
|
|
217
|
+
line = clipLine(line == null ? doc.size - 1: line);
|
|
139
218
|
return getStateBefore(line + 1);
|
|
140
219
|
},
|
|
141
|
-
cursorCoords: function(start){
|
|
220
|
+
cursorCoords: function(start, mode) {
|
|
142
221
|
if (start == null) start = sel.inverted;
|
|
143
|
-
return
|
|
222
|
+
return this.charCoords(start ? sel.from : sel.to, mode);
|
|
223
|
+
},
|
|
224
|
+
charCoords: function(pos, mode) {
|
|
225
|
+
pos = clipPos(pos);
|
|
226
|
+
if (mode == "local") return localCoords(pos, false);
|
|
227
|
+
if (mode == "div") return localCoords(pos, true);
|
|
228
|
+
return pageCoords(pos);
|
|
144
229
|
},
|
|
145
|
-
charCoords: function(pos){return pageCoords(clipPos(pos));},
|
|
146
230
|
coordsChar: function(coords) {
|
|
147
231
|
var off = eltOffset(lineSpace);
|
|
148
|
-
|
|
149
|
-
return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
|
|
232
|
+
return coordsChar(coords.x - off.left, coords.y - off.top);
|
|
150
233
|
},
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
234
|
+
markText: operation(markText),
|
|
235
|
+
setBookmark: setBookmark,
|
|
236
|
+
findMarksAt: findMarksAt,
|
|
237
|
+
setMarker: operation(addGutterMarker),
|
|
238
|
+
clearMarker: operation(removeGutterMarker),
|
|
155
239
|
setLineClass: operation(setLineClass),
|
|
240
|
+
hideLine: operation(function(h) {return setLineHidden(h, true);}),
|
|
241
|
+
showLine: operation(function(h) {return setLineHidden(h, false);}),
|
|
242
|
+
onDeleteLine: function(line, f) {
|
|
243
|
+
if (typeof line == "number") {
|
|
244
|
+
if (!isLine(line)) return null;
|
|
245
|
+
line = getLine(line);
|
|
246
|
+
}
|
|
247
|
+
(line.handlers || (line.handlers = [])).push(f);
|
|
248
|
+
return line;
|
|
249
|
+
},
|
|
156
250
|
lineInfo: lineInfo,
|
|
157
|
-
|
|
251
|
+
getViewport: function() { return {from: showingFrom, to: showingTo};},
|
|
252
|
+
addWidget: function(pos, node, scroll, vert, horiz) {
|
|
158
253
|
pos = localCoords(clipPos(pos));
|
|
159
254
|
var top = pos.yBot, left = pos.x;
|
|
160
255
|
node.style.position = "absolute";
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
|
|
256
|
+
sizer.appendChild(node);
|
|
257
|
+
if (vert == "over") top = pos.y;
|
|
258
|
+
else if (vert == "near") {
|
|
259
|
+
var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()),
|
|
260
|
+
hspace = Math.max(sizer.clientWidth, lineSpace.clientWidth) - paddingLeft();
|
|
167
261
|
if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
|
|
168
262
|
top = pos.y - node.offsetHeight;
|
|
169
263
|
if (left + node.offsetWidth > hspace)
|
|
170
264
|
left = hspace - node.offsetWidth;
|
|
171
265
|
}
|
|
172
266
|
node.style.top = (top + paddingTop()) + "px";
|
|
173
|
-
node.style.left =
|
|
267
|
+
node.style.left = node.style.right = "";
|
|
268
|
+
if (horiz == "right") {
|
|
269
|
+
left = sizer.clientWidth - node.offsetWidth;
|
|
270
|
+
node.style.right = "0px";
|
|
271
|
+
} else {
|
|
272
|
+
if (horiz == "left") left = 0;
|
|
273
|
+
else if (horiz == "middle") left = (sizer.clientWidth - node.offsetWidth) / 2;
|
|
274
|
+
node.style.left = (left + paddingLeft()) + "px";
|
|
275
|
+
}
|
|
174
276
|
if (scroll)
|
|
175
277
|
scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
|
|
176
278
|
},
|
|
177
279
|
|
|
178
|
-
lineCount: function() {return
|
|
280
|
+
lineCount: function() {return doc.size;},
|
|
281
|
+
clipPos: clipPos,
|
|
179
282
|
getCursor: function(start) {
|
|
180
283
|
if (start == null) start = sel.inverted;
|
|
181
284
|
return copyPos(start ? sel.from : sel.to);
|
|
182
285
|
},
|
|
183
286
|
somethingSelected: function() {return !posEq(sel.from, sel.to);},
|
|
184
|
-
setCursor: operation(function(line, ch) {
|
|
185
|
-
if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
|
|
186
|
-
else setCursor(line, ch);
|
|
287
|
+
setCursor: operation(function(line, ch, user) {
|
|
288
|
+
if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch, user);
|
|
289
|
+
else setCursor(line, ch, user);
|
|
290
|
+
}),
|
|
291
|
+
setSelection: operation(function(from, to, user) {
|
|
292
|
+
(user ? setSelectionUser : setSelection)(clipPos(from), clipPos(to || from));
|
|
187
293
|
}),
|
|
188
|
-
|
|
189
|
-
|
|
294
|
+
getLine: function(line) {if (isLine(line)) return getLine(line).text;},
|
|
295
|
+
getLineHandle: function(line) {if (isLine(line)) return getLine(line);},
|
|
190
296
|
setLine: operation(function(line, text) {
|
|
191
|
-
if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch:
|
|
297
|
+
if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
|
|
192
298
|
}),
|
|
193
299
|
removeLine: operation(function(line) {
|
|
194
300
|
if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
|
|
195
301
|
}),
|
|
196
302
|
replaceRange: operation(replaceRange),
|
|
197
|
-
getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
|
|
303
|
+
getRange: function(from, to, lineSep) {return getRange(clipPos(from), clipPos(to), lineSep);},
|
|
304
|
+
|
|
305
|
+
triggerOnKeyDown: operation(onKeyDown),
|
|
306
|
+
execCommand: function(cmd) {return commands[cmd](instance);},
|
|
307
|
+
// Stuff used by commands, probably not much use to outside code.
|
|
308
|
+
moveH: operation(moveH),
|
|
309
|
+
deleteH: operation(deleteH),
|
|
310
|
+
moveV: operation(moveV),
|
|
311
|
+
toggleOverwrite: function() {
|
|
312
|
+
if(overwrite){
|
|
313
|
+
overwrite = false;
|
|
314
|
+
cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
|
|
315
|
+
} else {
|
|
316
|
+
overwrite = true;
|
|
317
|
+
cursor.className += " CodeMirror-overwrite";
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
posFromIndex: function(off) {
|
|
322
|
+
var lineNo = 0, ch;
|
|
323
|
+
doc.iter(0, doc.size, function(line) {
|
|
324
|
+
var sz = line.text.length + 1;
|
|
325
|
+
if (sz > off) { ch = off; return true; }
|
|
326
|
+
off -= sz;
|
|
327
|
+
++lineNo;
|
|
328
|
+
});
|
|
329
|
+
return clipPos({line: lineNo, ch: ch});
|
|
330
|
+
},
|
|
331
|
+
indexFromPos: function (coords) {
|
|
332
|
+
if (coords.line < 0 || coords.ch < 0) return 0;
|
|
333
|
+
var index = coords.ch;
|
|
334
|
+
doc.iter(0, coords.line, function (line) {
|
|
335
|
+
index += line.text.length + 1;
|
|
336
|
+
});
|
|
337
|
+
return index;
|
|
338
|
+
},
|
|
339
|
+
scrollTo: function(x, y) {
|
|
340
|
+
if (x != null) scroller.scrollLeft = x;
|
|
341
|
+
if (y != null) scrollbar.scrollTop = scroller.scrollTop = y;
|
|
342
|
+
updateDisplay([]);
|
|
343
|
+
},
|
|
344
|
+
getScrollInfo: function() {
|
|
345
|
+
return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
|
|
346
|
+
height: scrollbar.scrollHeight, width: scroller.scrollWidth};
|
|
347
|
+
},
|
|
348
|
+
setSize: function(width, height) {
|
|
349
|
+
function interpret(val) {
|
|
350
|
+
val = String(val);
|
|
351
|
+
return /^\d+$/.test(val) ? val + "px" : val;
|
|
352
|
+
}
|
|
353
|
+
if (width != null) wrapper.style.width = interpret(width);
|
|
354
|
+
if (height != null) scroller.style.height = interpret(height);
|
|
355
|
+
instance.refresh();
|
|
356
|
+
},
|
|
198
357
|
|
|
199
358
|
operation: function(f){return operation(f)();},
|
|
200
|
-
|
|
359
|
+
compoundChange: function(f){return compoundChange(f);},
|
|
360
|
+
refresh: function(){
|
|
361
|
+
updateDisplay(true, null, lastScrollTop);
|
|
362
|
+
if (scrollbar.scrollHeight > lastScrollTop)
|
|
363
|
+
scrollbar.scrollTop = lastScrollTop;
|
|
364
|
+
},
|
|
201
365
|
getInputField: function(){return input;},
|
|
202
366
|
getWrapperElement: function(){return wrapper;},
|
|
203
|
-
getScrollerElement: function(){return scroller;}
|
|
367
|
+
getScrollerElement: function(){return scroller;},
|
|
368
|
+
getGutterElement: function(){return gutter;}
|
|
204
369
|
};
|
|
205
370
|
|
|
371
|
+
function getLine(n) { return getLineAt(doc, n); }
|
|
372
|
+
function updateLineHeight(line, height) {
|
|
373
|
+
gutterDirty = true;
|
|
374
|
+
var diff = height - line.height;
|
|
375
|
+
for (var n = line; n; n = n.parent) n.height += diff;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function lineContent(line, wrapAt) {
|
|
379
|
+
if (!line.styles)
|
|
380
|
+
line.highlight(mode, line.stateAfter = getStateBefore(lineNo(line)), options.tabSize);
|
|
381
|
+
return line.getContent(options.tabSize, wrapAt, options.lineWrapping);
|
|
382
|
+
}
|
|
383
|
+
|
|
206
384
|
function setValue(code) {
|
|
207
|
-
history = null;
|
|
208
385
|
var top = {line: 0, ch: 0};
|
|
209
|
-
updateLines(top, {line:
|
|
386
|
+
updateLines(top, {line: doc.size - 1, ch: getLine(doc.size-1).text.length},
|
|
210
387
|
splitLines(code), top, top);
|
|
211
|
-
|
|
388
|
+
updateInput = true;
|
|
212
389
|
}
|
|
213
|
-
function getValue(
|
|
390
|
+
function getValue(lineSep) {
|
|
214
391
|
var text = [];
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
392
|
+
doc.iter(0, doc.size, function(line) { text.push(line.text); });
|
|
393
|
+
return text.join(lineSep || "\n");
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function onScrollBar(e) {
|
|
397
|
+
if (scrollbar.scrollTop != lastScrollTop) {
|
|
398
|
+
lastScrollTop = scroller.scrollTop = scrollbar.scrollTop;
|
|
399
|
+
updateDisplay([]);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function onScrollMain(e) {
|
|
404
|
+
if (options.fixedGutter && gutter.style.left != scroller.scrollLeft + "px")
|
|
405
|
+
gutter.style.left = scroller.scrollLeft + "px";
|
|
406
|
+
if (scroller.scrollTop != lastScrollTop) {
|
|
407
|
+
lastScrollTop = scroller.scrollTop;
|
|
408
|
+
if (scrollbar.scrollTop != lastScrollTop)
|
|
409
|
+
scrollbar.scrollTop = lastScrollTop;
|
|
410
|
+
updateDisplay([]);
|
|
411
|
+
}
|
|
412
|
+
if (options.onScroll) options.onScroll(instance);
|
|
218
413
|
}
|
|
219
414
|
|
|
220
415
|
function onMouseDown(e) {
|
|
416
|
+
setShift(e_prop(e, "shiftKey"));
|
|
221
417
|
// Check whether this is a click in a widget
|
|
222
418
|
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
|
223
|
-
if (n.parentNode ==
|
|
224
|
-
|
|
225
|
-
//
|
|
419
|
+
if (n.parentNode == sizer && n != mover) return;
|
|
420
|
+
|
|
421
|
+
// See if this is a click in the gutter
|
|
226
422
|
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
|
227
423
|
if (n.parentNode == gutterText) {
|
|
228
424
|
if (options.onGutterClick)
|
|
229
|
-
options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom);
|
|
425
|
+
options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom, e);
|
|
230
426
|
return e_preventDefault(e);
|
|
231
427
|
}
|
|
232
428
|
|
|
233
429
|
var start = posFromMouse(e);
|
|
234
|
-
|
|
430
|
+
|
|
235
431
|
switch (e_button(e)) {
|
|
236
432
|
case 3:
|
|
237
|
-
if (gecko
|
|
433
|
+
if (gecko) onContextMenu(e);
|
|
238
434
|
return;
|
|
239
435
|
case 2:
|
|
240
436
|
if (start) setCursor(start.line, start.ch, true);
|
|
437
|
+
setTimeout(focusInput, 20);
|
|
438
|
+
e_preventDefault(e);
|
|
241
439
|
return;
|
|
242
440
|
}
|
|
243
441
|
// For button 1, if it was clicked inside the editor
|
|
@@ -246,24 +444,67 @@ var CodeMirror = (function() {
|
|
|
246
444
|
if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;}
|
|
247
445
|
|
|
248
446
|
if (!focused) onFocus();
|
|
249
|
-
e_preventDefault(e);
|
|
250
|
-
if (ld && +new Date - ld < 400) return selectLine(start.line);
|
|
251
447
|
|
|
252
|
-
|
|
448
|
+
var now = +new Date, type = "single";
|
|
449
|
+
if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
|
|
450
|
+
type = "triple";
|
|
451
|
+
e_preventDefault(e);
|
|
452
|
+
setTimeout(focusInput, 20);
|
|
453
|
+
selectLine(start.line);
|
|
454
|
+
} else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
|
|
455
|
+
type = "double";
|
|
456
|
+
lastDoubleClick = {time: now, pos: start};
|
|
457
|
+
e_preventDefault(e);
|
|
458
|
+
var word = findWordAt(start);
|
|
459
|
+
setSelectionUser(word.from, word.to);
|
|
460
|
+
} else { lastClick = {time: now, pos: start}; }
|
|
461
|
+
|
|
462
|
+
function dragEnd(e2) {
|
|
463
|
+
if (webkit) scroller.draggable = false;
|
|
464
|
+
draggingText = false;
|
|
465
|
+
up(); drop();
|
|
466
|
+
if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
|
|
467
|
+
e_preventDefault(e2);
|
|
468
|
+
setCursor(start.line, start.ch, true);
|
|
469
|
+
focusInput();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
253
472
|
var last = start, going;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
473
|
+
if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
|
|
474
|
+
!posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
|
|
475
|
+
// Let the drag handler handle this.
|
|
476
|
+
if (webkit) scroller.draggable = true;
|
|
477
|
+
var up = connect(document, "mouseup", operation(dragEnd), true);
|
|
478
|
+
var drop = connect(scroller, "drop", operation(dragEnd), true);
|
|
479
|
+
draggingText = true;
|
|
480
|
+
// IE's approach to draggable
|
|
481
|
+
if (scroller.dragDrop) scroller.dragDrop();
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
e_preventDefault(e);
|
|
485
|
+
if (type == "single") setCursor(start.line, start.ch, true);
|
|
486
|
+
|
|
487
|
+
var startstart = sel.from, startend = sel.to;
|
|
488
|
+
|
|
489
|
+
function doSelect(cur) {
|
|
490
|
+
if (type == "single") {
|
|
491
|
+
setSelectionUser(start, cur);
|
|
492
|
+
} else if (type == "double") {
|
|
493
|
+
var word = findWordAt(cur);
|
|
494
|
+
if (posLess(cur, startstart)) setSelectionUser(word.from, startend);
|
|
495
|
+
else setSelectionUser(startstart, word.to);
|
|
496
|
+
} else if (type == "triple") {
|
|
497
|
+
if (posLess(cur, startstart)) setSelectionUser(startend, clipPos({line: cur.line, ch: 0}));
|
|
498
|
+
else setSelectionUser(startstart, clipPos({line: cur.line + 1, ch: 0}));
|
|
499
|
+
}
|
|
260
500
|
}
|
|
501
|
+
|
|
261
502
|
function extend(e) {
|
|
262
503
|
var cur = posFromMouse(e, true);
|
|
263
504
|
if (cur && !posEq(cur, last)) {
|
|
264
505
|
if (!focused) onFocus();
|
|
265
506
|
last = cur;
|
|
266
|
-
|
|
507
|
+
doSelect(cur);
|
|
267
508
|
updateInput = false;
|
|
268
509
|
var visible = visibleLines();
|
|
269
510
|
if (cur.line >= visible.to || cur.line < visible.from)
|
|
@@ -271,112 +512,179 @@ var CodeMirror = (function() {
|
|
|
271
512
|
}
|
|
272
513
|
}
|
|
273
514
|
|
|
274
|
-
|
|
515
|
+
function done(e) {
|
|
275
516
|
clearTimeout(going);
|
|
517
|
+
var cur = posFromMouse(e);
|
|
518
|
+
if (cur) doSelect(cur);
|
|
276
519
|
e_preventDefault(e);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
520
|
+
focusInput();
|
|
521
|
+
updateInput = true;
|
|
522
|
+
move(); up();
|
|
523
|
+
}
|
|
524
|
+
var move = connect(document, "mousemove", operation(function(e) {
|
|
280
525
|
clearTimeout(going);
|
|
281
|
-
var cur = posFromMouse(e);
|
|
282
|
-
if (cur) setSelectionUser(start, cur);
|
|
283
526
|
e_preventDefault(e);
|
|
284
|
-
|
|
527
|
+
if (!ie && !e_button(e)) done(e);
|
|
528
|
+
else extend(e);
|
|
285
529
|
}), true);
|
|
530
|
+
var up = connect(document, "mouseup", operation(done), true);
|
|
286
531
|
}
|
|
287
|
-
function
|
|
288
|
-
var
|
|
289
|
-
|
|
290
|
-
selectWordAt(pos);
|
|
532
|
+
function onDoubleClick(e) {
|
|
533
|
+
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
|
534
|
+
if (n.parentNode == gutterText) return e_preventDefault(e);
|
|
291
535
|
e_preventDefault(e);
|
|
292
|
-
lastDoubleClick = +new Date;
|
|
293
536
|
}
|
|
294
537
|
function onDrop(e) {
|
|
295
|
-
|
|
538
|
+
if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
|
|
539
|
+
e_preventDefault(e);
|
|
296
540
|
var pos = posFromMouse(e, true), files = e.dataTransfer.files;
|
|
297
541
|
if (!pos || options.readOnly) return;
|
|
298
542
|
if (files && files.length && window.FileReader && window.File) {
|
|
299
|
-
|
|
543
|
+
var n = files.length, text = Array(n), read = 0;
|
|
544
|
+
var loadFile = function(file, i) {
|
|
300
545
|
var reader = new FileReader;
|
|
301
546
|
reader.onload = function() {
|
|
302
547
|
text[i] = reader.result;
|
|
303
|
-
if (++read == n)
|
|
548
|
+
if (++read == n) {
|
|
549
|
+
pos = clipPos(pos);
|
|
550
|
+
operation(function() {
|
|
551
|
+
var end = replaceRange(text.join(""), pos, pos);
|
|
552
|
+
setSelectionUser(pos, end);
|
|
553
|
+
})();
|
|
554
|
+
}
|
|
304
555
|
};
|
|
305
556
|
reader.readAsText(file);
|
|
306
|
-
}
|
|
307
|
-
var n = files.length, text = Array(n), read = 0;
|
|
557
|
+
};
|
|
308
558
|
for (var i = 0; i < n; ++i) loadFile(files[i], i);
|
|
309
|
-
}
|
|
310
|
-
|
|
559
|
+
} else {
|
|
560
|
+
// Don't do a replace if the drop happened inside of the selected text.
|
|
561
|
+
if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
|
|
311
562
|
try {
|
|
312
563
|
var text = e.dataTransfer.getData("Text");
|
|
313
|
-
if (text)
|
|
564
|
+
if (text) {
|
|
565
|
+
compoundChange(function() {
|
|
566
|
+
var curFrom = sel.from, curTo = sel.to;
|
|
567
|
+
setSelectionUser(pos, pos);
|
|
568
|
+
if (draggingText) replaceRange("", curFrom, curTo);
|
|
569
|
+
replaceSelection(text);
|
|
570
|
+
focusInput();
|
|
571
|
+
});
|
|
572
|
+
}
|
|
314
573
|
}
|
|
315
574
|
catch(e){}
|
|
316
575
|
}
|
|
317
576
|
}
|
|
318
|
-
function
|
|
319
|
-
|
|
577
|
+
function onDragStart(e) {
|
|
578
|
+
var txt = getSelection();
|
|
579
|
+
e.dataTransfer.setData("Text", txt);
|
|
320
580
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
var mod = (mac ? e.metaKey : e.ctrlKey) && !e.altKey, anyMod = e.ctrlKey || e.altKey || e.metaKey;
|
|
326
|
-
if (code == 16 || e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
|
|
327
|
-
else shiftSelecting = null;
|
|
328
|
-
// First give onKeyEvent option a chance to handle this.
|
|
329
|
-
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
|
581
|
+
// Use dummy image instead of default browsers image.
|
|
582
|
+
if (e.dataTransfer.setDragImage)
|
|
583
|
+
e.dataTransfer.setDragImage(elt('img'), 0, 0);
|
|
584
|
+
}
|
|
330
585
|
|
|
331
|
-
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (
|
|
339
|
-
if (
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
586
|
+
function doHandleBinding(bound, dropShift) {
|
|
587
|
+
if (typeof bound == "string") {
|
|
588
|
+
bound = commands[bound];
|
|
589
|
+
if (!bound) return false;
|
|
590
|
+
}
|
|
591
|
+
var prevShift = shiftSelecting;
|
|
592
|
+
try {
|
|
593
|
+
if (options.readOnly) suppressEdits = true;
|
|
594
|
+
if (dropShift) shiftSelecting = null;
|
|
595
|
+
bound(instance);
|
|
596
|
+
} catch(e) {
|
|
597
|
+
if (e != Pass) throw e;
|
|
598
|
+
return false;
|
|
599
|
+
} finally {
|
|
600
|
+
shiftSelecting = prevShift;
|
|
601
|
+
suppressEdits = false;
|
|
602
|
+
}
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
var maybeTransition;
|
|
606
|
+
function handleKeyBinding(e) {
|
|
607
|
+
// Handle auto keymap transitions
|
|
608
|
+
var startMap = getKeyMap(options.keyMap), next = startMap.auto;
|
|
609
|
+
clearTimeout(maybeTransition);
|
|
610
|
+
if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
|
|
611
|
+
if (getKeyMap(options.keyMap) == startMap) {
|
|
612
|
+
options.keyMap = (next.call ? next.call(null, instance) : next);
|
|
356
613
|
}
|
|
614
|
+
}, 50);
|
|
615
|
+
|
|
616
|
+
var name = keyNames[e_prop(e, "keyCode")], handled = false;
|
|
617
|
+
var flipCtrlCmd = opera && mac;
|
|
618
|
+
if (name == null || e.altGraphKey) return false;
|
|
619
|
+
if (e_prop(e, "altKey")) name = "Alt-" + name;
|
|
620
|
+
if (e_prop(e, flipCtrlCmd ? "metaKey" : "ctrlKey")) name = "Ctrl-" + name;
|
|
621
|
+
if (e_prop(e, flipCtrlCmd ? "ctrlKey" : "metaKey")) name = "Cmd-" + name;
|
|
622
|
+
|
|
623
|
+
var stopped = false;
|
|
624
|
+
function stop() { stopped = true; }
|
|
625
|
+
|
|
626
|
+
if (e_prop(e, "shiftKey")) {
|
|
627
|
+
handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
|
|
628
|
+
function(b) {return doHandleBinding(b, true);}, stop)
|
|
629
|
+
|| lookupKey(name, options.extraKeys, options.keyMap, function(b) {
|
|
630
|
+
if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
|
|
631
|
+
}, stop);
|
|
632
|
+
} else {
|
|
633
|
+
handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
|
|
634
|
+
}
|
|
635
|
+
if (stopped) handled = false;
|
|
636
|
+
if (handled) {
|
|
637
|
+
e_preventDefault(e);
|
|
638
|
+
restartBlink();
|
|
639
|
+
if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
|
|
357
640
|
}
|
|
358
|
-
|
|
641
|
+
return handled;
|
|
359
642
|
}
|
|
360
|
-
function
|
|
643
|
+
function handleCharBinding(e, ch) {
|
|
644
|
+
var handled = lookupKey("'" + ch + "'", options.extraKeys,
|
|
645
|
+
options.keyMap, function(b) { return doHandleBinding(b, true); });
|
|
646
|
+
if (handled) {
|
|
647
|
+
e_preventDefault(e);
|
|
648
|
+
restartBlink();
|
|
649
|
+
}
|
|
650
|
+
return handled;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
var lastStoppedKey = null;
|
|
654
|
+
function onKeyDown(e) {
|
|
655
|
+
if (!focused) onFocus();
|
|
656
|
+
if (ie && e.keyCode == 27) { e.returnValue = false; }
|
|
657
|
+
if (pollingFast) { if (readInput()) pollingFast = false; }
|
|
361
658
|
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
659
|
+
var code = e_prop(e, "keyCode");
|
|
660
|
+
// IE does strange things with escape.
|
|
661
|
+
setShift(code == 16 || e_prop(e, "shiftKey"));
|
|
662
|
+
// First give onKeyEvent option a chance to handle this.
|
|
663
|
+
var handled = handleKeyBinding(e);
|
|
664
|
+
if (opera) {
|
|
665
|
+
lastStoppedKey = handled ? code : null;
|
|
666
|
+
// Opera has no cut event... we try to at least catch the key combo
|
|
667
|
+
if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
|
|
668
|
+
replaceSelection("");
|
|
365
669
|
}
|
|
366
|
-
if (e.keyCode == 16) shiftSelecting = null;
|
|
367
670
|
}
|
|
368
671
|
function onKeyPress(e) {
|
|
672
|
+
if (pollingFast) readInput();
|
|
369
673
|
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
|
370
|
-
|
|
371
|
-
|
|
674
|
+
var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
|
|
675
|
+
if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
|
|
676
|
+
if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
|
|
677
|
+
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
|
|
678
|
+
if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
|
|
372
679
|
if (mode.electricChars.indexOf(ch) > -1)
|
|
373
|
-
setTimeout(operation(function() {indentLine(sel.to.line, "smart");}),
|
|
680
|
+
setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
|
|
374
681
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
682
|
+
if (handleCharBinding(e, ch)) return;
|
|
683
|
+
fastPoll();
|
|
684
|
+
}
|
|
685
|
+
function onKeyUp(e) {
|
|
686
|
+
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
|
687
|
+
if (e_prop(e, "keyCode") == 16) shiftSelecting = null;
|
|
380
688
|
}
|
|
381
689
|
|
|
382
690
|
function onFocus() {
|
|
@@ -384,9 +692,8 @@ var CodeMirror = (function() {
|
|
|
384
692
|
if (!focused) {
|
|
385
693
|
if (options.onFocus) options.onFocus(instance);
|
|
386
694
|
focused = true;
|
|
387
|
-
if (
|
|
388
|
-
|
|
389
|
-
if (!leaveInputAlone) prepareInput();
|
|
695
|
+
if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
|
|
696
|
+
scroller.className += " CodeMirror-focused";
|
|
390
697
|
}
|
|
391
698
|
slowPoll();
|
|
392
699
|
restartBlink();
|
|
@@ -395,7 +702,11 @@ var CodeMirror = (function() {
|
|
|
395
702
|
if (focused) {
|
|
396
703
|
if (options.onBlur) options.onBlur(instance);
|
|
397
704
|
focused = false;
|
|
398
|
-
|
|
705
|
+
if (bracketHighlighted)
|
|
706
|
+
operation(function(){
|
|
707
|
+
if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
|
|
708
|
+
})();
|
|
709
|
+
scroller.className = scroller.className.replace(" CodeMirror-focused", "");
|
|
399
710
|
}
|
|
400
711
|
clearInterval(blinker);
|
|
401
712
|
setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
|
|
@@ -404,105 +715,166 @@ var CodeMirror = (function() {
|
|
|
404
715
|
// Replace the range from from to to by the strings in newText.
|
|
405
716
|
// Afterwards, set the selection to selFrom, selTo.
|
|
406
717
|
function updateLines(from, to, newText, selFrom, selTo) {
|
|
718
|
+
if (suppressEdits) return;
|
|
719
|
+
var old = [];
|
|
720
|
+
doc.iter(from.line, to.line + 1, function(line) {
|
|
721
|
+
old.push(newHL(line.text, line.markedSpans));
|
|
722
|
+
});
|
|
407
723
|
if (history) {
|
|
408
|
-
var old = [];
|
|
409
|
-
for (var i = from.line, e = to.line + 1; i < e; ++i) old.push(lines[i].text);
|
|
410
724
|
history.addChange(from.line, newText.length, old);
|
|
411
725
|
while (history.done.length > options.undoDepth) history.done.shift();
|
|
412
726
|
}
|
|
413
|
-
|
|
727
|
+
var lines = updateMarkedSpans(hlSpans(old[0]), hlSpans(lst(old)), from.ch, to.ch, newText);
|
|
728
|
+
updateLinesNoUndo(from, to, lines, selFrom, selTo);
|
|
414
729
|
}
|
|
415
730
|
function unredoHelper(from, to) {
|
|
416
|
-
|
|
417
|
-
|
|
731
|
+
if (!from.length) return;
|
|
732
|
+
var set = from.pop(), out = [];
|
|
733
|
+
for (var i = set.length - 1; i >= 0; i -= 1) {
|
|
734
|
+
var change = set[i];
|
|
418
735
|
var replaced = [], end = change.start + change.added;
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
var pos =
|
|
422
|
-
|
|
423
|
-
updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch:
|
|
424
|
-
|
|
736
|
+
doc.iter(change.start, end, function(line) { replaced.push(newHL(line.text, line.markedSpans)); });
|
|
737
|
+
out.push({start: change.start, added: change.old.length, old: replaced});
|
|
738
|
+
var pos = {line: change.start + change.old.length - 1,
|
|
739
|
+
ch: editEnd(hlText(lst(replaced)), hlText(lst(change.old)))};
|
|
740
|
+
updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length},
|
|
741
|
+
change.old, pos, pos);
|
|
425
742
|
}
|
|
743
|
+
updateInput = true;
|
|
744
|
+
to.push(out);
|
|
426
745
|
}
|
|
427
746
|
function undo() {unredoHelper(history.done, history.undone);}
|
|
428
747
|
function redo() {unredoHelper(history.undone, history.done);}
|
|
429
748
|
|
|
430
|
-
function updateLinesNoUndo(from, to,
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
749
|
+
function updateLinesNoUndo(from, to, lines, selFrom, selTo) {
|
|
750
|
+
if (suppressEdits) return;
|
|
751
|
+
var recomputeMaxLength = false, maxLineLength = maxLine.text.length;
|
|
752
|
+
if (!options.lineWrapping)
|
|
753
|
+
doc.iter(from.line, to.line + 1, function(line) {
|
|
754
|
+
if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
|
|
755
|
+
});
|
|
756
|
+
if (from.line != to.line || lines.length > 1) gutterDirty = true;
|
|
757
|
+
|
|
758
|
+
var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line);
|
|
759
|
+
var lastHL = lst(lines);
|
|
760
|
+
|
|
761
|
+
// First adjust the line structure
|
|
762
|
+
if (from.ch == 0 && to.ch == 0 && hlText(lastHL) == "") {
|
|
763
|
+
// This is a whole-line replace. Treated specially to make
|
|
764
|
+
// sure line objects move the way they are supposed to.
|
|
765
|
+
var added = [], prevLine = null;
|
|
766
|
+
for (var i = 0, e = lines.length - 1; i < e; ++i)
|
|
767
|
+
added.push(new Line(hlText(lines[i]), hlSpans(lines[i])));
|
|
768
|
+
lastLine.update(lastLine.text, hlSpans(lastHL));
|
|
769
|
+
if (nlines) doc.remove(from.line, nlines, callbacks);
|
|
770
|
+
if (added.length) doc.insert(from.line, added);
|
|
771
|
+
} else if (firstLine == lastLine) {
|
|
772
|
+
if (lines.length == 1) {
|
|
773
|
+
firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]) + firstLine.text.slice(to.ch), hlSpans(lines[0]));
|
|
774
|
+
} else {
|
|
775
|
+
for (var added = [], i = 1, e = lines.length - 1; i < e; ++i)
|
|
776
|
+
added.push(new Line(hlText(lines[i]), hlSpans(lines[i])));
|
|
777
|
+
added.push(new Line(hlText(lastHL) + firstLine.text.slice(to.ch), hlSpans(lastHL)));
|
|
778
|
+
firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
|
|
779
|
+
doc.insert(from.line + 1, added);
|
|
448
780
|
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
if (l.length > maxLineLength) {
|
|
475
|
-
maxLineLength = l.length; maxLine = l;
|
|
781
|
+
} else if (lines.length == 1) {
|
|
782
|
+
firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]) + lastLine.text.slice(to.ch), hlSpans(lines[0]));
|
|
783
|
+
doc.remove(from.line + 1, nlines, callbacks);
|
|
784
|
+
} else {
|
|
785
|
+
var added = [];
|
|
786
|
+
firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
|
|
787
|
+
lastLine.update(hlText(lastHL) + lastLine.text.slice(to.ch), hlSpans(lastHL));
|
|
788
|
+
for (var i = 1, e = lines.length - 1; i < e; ++i)
|
|
789
|
+
added.push(new Line(hlText(lines[i]), hlSpans(lines[i])));
|
|
790
|
+
if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks);
|
|
791
|
+
doc.insert(from.line + 1, added);
|
|
792
|
+
}
|
|
793
|
+
if (options.lineWrapping) {
|
|
794
|
+
var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
|
|
795
|
+
doc.iter(from.line, from.line + lines.length, function(line) {
|
|
796
|
+
if (line.hidden) return;
|
|
797
|
+
var guess = Math.ceil(line.text.length / perLine) || 1;
|
|
798
|
+
if (guess != line.height) updateLineHeight(line, guess);
|
|
799
|
+
});
|
|
800
|
+
} else {
|
|
801
|
+
doc.iter(from.line, from.line + lines.length, function(line) {
|
|
802
|
+
var l = line.text;
|
|
803
|
+
if (!line.hidden && l.length > maxLineLength) {
|
|
804
|
+
maxLine = line; maxLineLength = l.length; maxLineChanged = true;
|
|
805
|
+
recomputeMaxLength = false;
|
|
476
806
|
}
|
|
477
|
-
}
|
|
807
|
+
});
|
|
808
|
+
if (recomputeMaxLength) updateMaxLine = true;
|
|
478
809
|
}
|
|
479
810
|
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
if (task < from.line) newWork.push(task);
|
|
486
|
-
else if (task > to.line) newWork.push(task + lendiff);
|
|
487
|
-
}
|
|
488
|
-
if (newText.length < 5) {
|
|
489
|
-
highlightLines(from.line, from.line + newText.length);
|
|
490
|
-
newWork.push(from.line + newText.length);
|
|
491
|
-
} else {
|
|
492
|
-
newWork.push(from.line);
|
|
493
|
-
}
|
|
494
|
-
work = newWork;
|
|
495
|
-
startWorker(100);
|
|
811
|
+
// Adjust frontier, schedule worker
|
|
812
|
+
frontier = Math.min(frontier, from.line);
|
|
813
|
+
startWorker(400);
|
|
814
|
+
|
|
815
|
+
var lendiff = lines.length - nlines - 1;
|
|
496
816
|
// Remember that these lines changed, for updating the display
|
|
497
817
|
changes.push({from: from.line, to: to.line + 1, diff: lendiff});
|
|
498
|
-
|
|
818
|
+
if (options.onChange) {
|
|
819
|
+
// Normalize lines to contain only strings, since that's what
|
|
820
|
+
// the change event handler expects
|
|
821
|
+
for (var i = 0; i < lines.length; ++i)
|
|
822
|
+
if (typeof lines[i] != "string") lines[i] = lines[i].text;
|
|
823
|
+
var changeObj = {from: from, to: to, text: lines};
|
|
824
|
+
if (textChanged) {
|
|
825
|
+
for (var cur = textChanged; cur.next; cur = cur.next) {}
|
|
826
|
+
cur.next = changeObj;
|
|
827
|
+
} else textChanged = changeObj;
|
|
828
|
+
}
|
|
499
829
|
|
|
500
830
|
// Update the selection
|
|
501
831
|
function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
|
|
502
|
-
setSelection(selFrom, selTo
|
|
832
|
+
setSelection(clipPos(selFrom), clipPos(selTo),
|
|
833
|
+
updateLine(sel.from.line), updateLine(sel.to.line));
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function needsScrollbar() {
|
|
837
|
+
var realHeight = doc.height * textHeight() + 2 * paddingTop();
|
|
838
|
+
return realHeight * .99 > scroller.offsetHeight ? realHeight : false;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function updateVerticalScroll(scrollTop) {
|
|
842
|
+
var scrollHeight = needsScrollbar();
|
|
843
|
+
scrollbar.style.display = scrollHeight ? "block" : "none";
|
|
844
|
+
if (scrollHeight) {
|
|
845
|
+
scrollbarInner.style.height = sizer.style.minHeight = scrollHeight + "px";
|
|
846
|
+
scrollbar.style.height = scroller.clientHeight + "px";
|
|
847
|
+
if (scrollTop != null) {
|
|
848
|
+
scrollbar.scrollTop = scroller.scrollTop = scrollTop;
|
|
849
|
+
// 'Nudge' the scrollbar to work around a Webkit bug where,
|
|
850
|
+
// in some situations, we'd end up with a scrollbar that
|
|
851
|
+
// reported its scrollTop (and looked) as expected, but
|
|
852
|
+
// *behaved* as if it was still in a previous state (i.e.
|
|
853
|
+
// couldn't scroll up, even though it appeared to be at the
|
|
854
|
+
// bottom).
|
|
855
|
+
if (webkit) setTimeout(function() {
|
|
856
|
+
if (scrollbar.scrollTop != scrollTop) return;
|
|
857
|
+
scrollbar.scrollTop = scrollTop + (scrollTop ? -1 : 1);
|
|
858
|
+
scrollbar.scrollTop = scrollTop;
|
|
859
|
+
}, 0);
|
|
860
|
+
}
|
|
861
|
+
} else {
|
|
862
|
+
sizer.style.minHeight = "";
|
|
863
|
+
}
|
|
864
|
+
// Position the mover div to align with the current virtual scroll position
|
|
865
|
+
mover.style.top = displayOffset * textHeight() + "px";
|
|
866
|
+
}
|
|
503
867
|
|
|
504
|
-
|
|
505
|
-
|
|
868
|
+
function computeMaxLength() {
|
|
869
|
+
maxLine = getLine(0); maxLineChanged = true;
|
|
870
|
+
var maxLineLength = maxLine.text.length;
|
|
871
|
+
doc.iter(1, doc.size, function(line) {
|
|
872
|
+
var l = line.text;
|
|
873
|
+
if (!line.hidden && l.length > maxLineLength) {
|
|
874
|
+
maxLineLength = l.length; maxLine = line;
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
updateMaxLine = false;
|
|
506
878
|
}
|
|
507
879
|
|
|
508
880
|
function replaceRange(code, from, to) {
|
|
@@ -515,7 +887,7 @@ var CodeMirror = (function() {
|
|
|
515
887
|
var line = pos.line + code.length - (to.line - from.line) - 1;
|
|
516
888
|
var ch = pos.ch;
|
|
517
889
|
if (pos.line == to.line)
|
|
518
|
-
ch += code
|
|
890
|
+
ch += lst(code).length - (to.ch - (to.line == from.line ? from.ch : 0));
|
|
519
891
|
return {line: line, ch: ch};
|
|
520
892
|
}
|
|
521
893
|
var end;
|
|
@@ -533,189 +905,241 @@ var CodeMirror = (function() {
|
|
|
533
905
|
});
|
|
534
906
|
}
|
|
535
907
|
function replaceRange1(code, from, to, computeSel) {
|
|
536
|
-
var endch = code.length == 1 ? code[0].length + from.ch : code
|
|
908
|
+
var endch = code.length == 1 ? code[0].length + from.ch : lst(code).length;
|
|
537
909
|
var newSel = computeSel({line: from.line + code.length - 1, ch: endch});
|
|
538
910
|
updateLines(from, to, code, newSel.from, newSel.to);
|
|
539
911
|
}
|
|
540
912
|
|
|
541
|
-
function getRange(from, to) {
|
|
913
|
+
function getRange(from, to, lineSep) {
|
|
542
914
|
var l1 = from.line, l2 = to.line;
|
|
543
|
-
if (l1 == l2) return
|
|
544
|
-
var code = [
|
|
545
|
-
|
|
546
|
-
code.push(
|
|
547
|
-
return code.join("\n");
|
|
915
|
+
if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
|
|
916
|
+
var code = [getLine(l1).text.slice(from.ch)];
|
|
917
|
+
doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
|
|
918
|
+
code.push(getLine(l2).text.slice(0, to.ch));
|
|
919
|
+
return code.join(lineSep || "\n");
|
|
548
920
|
}
|
|
549
|
-
function getSelection() {
|
|
550
|
-
return getRange(sel.from, sel.to);
|
|
921
|
+
function getSelection(lineSep) {
|
|
922
|
+
return getRange(sel.from, sel.to, lineSep);
|
|
551
923
|
}
|
|
552
924
|
|
|
553
|
-
var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
|
|
554
925
|
function slowPoll() {
|
|
555
926
|
if (pollingFast) return;
|
|
556
|
-
poll.set(
|
|
557
|
-
startOperation();
|
|
927
|
+
poll.set(options.pollInterval, function() {
|
|
558
928
|
readInput();
|
|
559
929
|
if (focused) slowPoll();
|
|
560
|
-
endOperation();
|
|
561
930
|
});
|
|
562
931
|
}
|
|
563
|
-
function fastPoll(
|
|
932
|
+
function fastPoll() {
|
|
564
933
|
var missed = false;
|
|
565
934
|
pollingFast = true;
|
|
566
935
|
function p() {
|
|
567
|
-
startOperation();
|
|
568
936
|
var changed = readInput();
|
|
569
|
-
if (changed
|
|
570
|
-
if (!changed && !missed) {missed = true; poll.set(80, p);}
|
|
937
|
+
if (!changed && !missed) {missed = true; poll.set(60, p);}
|
|
571
938
|
else {pollingFast = false; slowPoll();}
|
|
572
|
-
endOperation();
|
|
573
939
|
}
|
|
574
940
|
poll.set(20, p);
|
|
575
941
|
}
|
|
576
942
|
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
//
|
|
943
|
+
// Previnput is a hack to work with IME. If we reset the textarea
|
|
944
|
+
// on every change, that breaks IME. So we look for changes
|
|
945
|
+
// compared to the previous content instead. (Modern browsers have
|
|
946
|
+
// events that indicate IME taking place, but these are not widely
|
|
947
|
+
// supported or compatible enough yet to rely on.)
|
|
948
|
+
var prevInput = "";
|
|
580
949
|
function readInput() {
|
|
581
|
-
if (
|
|
582
|
-
var
|
|
583
|
-
if (
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
if (found == -1 || (text.charAt(found-1) == "\r" ? found - 1 : found) >= n)
|
|
598
|
-
return {line: startLine, ch: n - pos};
|
|
599
|
-
++startLine;
|
|
600
|
-
pos = found + 1;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
var from = computeOffset(sr.start, editing.from),
|
|
604
|
-
to = computeOffset(sr.end, editing.from);
|
|
605
|
-
// Here we have to take the reducedSelection hack into account,
|
|
606
|
-
// so that you can, for example, press shift-up at the start of
|
|
607
|
-
// your selection and have the right thing happen.
|
|
608
|
-
if (rs) {
|
|
609
|
-
var head = sr.start == rs.anchor ? to : from;
|
|
610
|
-
var tail = shiftSelecting ? sel.to : sr.start == rs.anchor ? from : to;
|
|
611
|
-
if (sel.inverted = posLess(head, tail)) { from = head; to = tail; }
|
|
612
|
-
else { reducedSelection = null; from = tail; to = head; }
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// In some cases (cursor on same line as before), we don't have
|
|
616
|
-
// to update the textarea content at all.
|
|
617
|
-
if (from.line == to.line && from.line == sel.from.line && from.line == sel.to.line && !shiftSelecting)
|
|
618
|
-
updateInput = false;
|
|
619
|
-
|
|
620
|
-
// Magic mess to extract precise edited range from the changed
|
|
621
|
-
// string.
|
|
622
|
-
if (changed) {
|
|
623
|
-
var start = 0, end = text.length, len = Math.min(end, editing.text.length);
|
|
624
|
-
var c, line = editing.from, nl = -1;
|
|
625
|
-
while (start < len && (c = text.charAt(start)) == editing.text.charAt(start)) {
|
|
626
|
-
++start;
|
|
627
|
-
if (c == "\n") {line++; nl = start;}
|
|
628
|
-
}
|
|
629
|
-
var ch = nl > -1 ? start - nl : start, endline = editing.to - 1, edend = editing.text.length;
|
|
630
|
-
for (;;) {
|
|
631
|
-
c = editing.text.charAt(edend);
|
|
632
|
-
if (text.charAt(end) != c) {++end; ++edend; break;}
|
|
633
|
-
if (c == "\n") endline--;
|
|
634
|
-
if (edend <= start || end <= start) break;
|
|
635
|
-
--end; --edend;
|
|
636
|
-
}
|
|
637
|
-
var nl = editing.text.lastIndexOf("\n", edend - 1), endch = nl == -1 ? edend : edend - nl - 1;
|
|
638
|
-
updateLines({line: line, ch: ch}, {line: endline, ch: endch}, splitLines(text.slice(start, end)), from, to);
|
|
639
|
-
if (line != endline || from.line != line) updateInput = true;
|
|
640
|
-
}
|
|
641
|
-
else setSelection(from, to);
|
|
642
|
-
|
|
643
|
-
editing.text = text; editing.start = sr.start; editing.end = sr.end;
|
|
644
|
-
return changed ? "changed" : moved ? "moved" : false;
|
|
950
|
+
if (!focused || hasSelection(input) || options.readOnly) return false;
|
|
951
|
+
var text = input.value;
|
|
952
|
+
if (text == prevInput) return false;
|
|
953
|
+
if (!nestedOperation) startOperation();
|
|
954
|
+
shiftSelecting = null;
|
|
955
|
+
var same = 0, l = Math.min(prevInput.length, text.length);
|
|
956
|
+
while (same < l && prevInput[same] == text[same]) ++same;
|
|
957
|
+
if (same < prevInput.length)
|
|
958
|
+
sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)};
|
|
959
|
+
else if (overwrite && posEq(sel.from, sel.to))
|
|
960
|
+
sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
|
|
961
|
+
replaceSelection(text.slice(same), "end");
|
|
962
|
+
if (text.length > 1000) { input.value = prevInput = ""; }
|
|
963
|
+
else prevInput = text;
|
|
964
|
+
if (!nestedOperation) endOperation();
|
|
965
|
+
return true;
|
|
645
966
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
for (var i = from; i < to; ++i) text.push(lines[i].text);
|
|
653
|
-
text = input.value = text.join(lineSep);
|
|
654
|
-
var startch = sel.from.ch, endch = sel.to.ch;
|
|
655
|
-
for (var i = from; i < sel.from.line; ++i)
|
|
656
|
-
startch += lineSep.length + lines[i].text.length;
|
|
657
|
-
for (var i = from; i < sel.to.line; ++i)
|
|
658
|
-
endch += lineSep.length + lines[i].text.length;
|
|
659
|
-
editing = {text: text, from: from, to: to, start: startch, end: endch};
|
|
660
|
-
setSelRange(input, startch, reducedSelection ? startch : endch);
|
|
967
|
+
function resetInput(user) {
|
|
968
|
+
if (!posEq(sel.from, sel.to)) {
|
|
969
|
+
prevInput = "";
|
|
970
|
+
input.value = getSelection();
|
|
971
|
+
if (focused) selectInput(input);
|
|
972
|
+
} else if (user) prevInput = input.value = "";
|
|
661
973
|
}
|
|
974
|
+
|
|
662
975
|
function focusInput() {
|
|
663
976
|
if (options.readOnly != "nocursor") input.focus();
|
|
664
977
|
}
|
|
665
978
|
|
|
666
979
|
function scrollCursorIntoView() {
|
|
980
|
+
var coords = calculateCursorCoords();
|
|
981
|
+
scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
|
|
982
|
+
if (!focused) return;
|
|
983
|
+
var box = sizer.getBoundingClientRect(), doScroll = null;
|
|
984
|
+
if (coords.y + box.top < 0) doScroll = true;
|
|
985
|
+
else if (coords.y + box.top + textHeight() > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
|
|
986
|
+
if (doScroll != null) {
|
|
987
|
+
var hidden = cursor.style.display == "none";
|
|
988
|
+
if (hidden) {
|
|
989
|
+
cursor.style.display = "";
|
|
990
|
+
cursor.style.left = coords.x + "px";
|
|
991
|
+
cursor.style.top = (coords.y - displayOffset) + "px";
|
|
992
|
+
}
|
|
993
|
+
cursor.scrollIntoView(doScroll);
|
|
994
|
+
if (hidden) cursor.style.display = "none";
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
function calculateCursorCoords() {
|
|
667
998
|
var cursor = localCoords(sel.inverted ? sel.from : sel.to);
|
|
668
|
-
|
|
999
|
+
var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
|
|
1000
|
+
return {x: x, y: cursor.y, yBot: cursor.yBot};
|
|
669
1001
|
}
|
|
670
1002
|
function scrollIntoView(x1, y1, x2, y2) {
|
|
671
|
-
var
|
|
1003
|
+
var scrollPos = calculateScrollPos(x1, y1, x2, y2);
|
|
1004
|
+
if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft;}
|
|
1005
|
+
if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scroller.scrollTop = scrollPos.scrollTop;}
|
|
1006
|
+
}
|
|
1007
|
+
function calculateScrollPos(x1, y1, x2, y2) {
|
|
1008
|
+
var pl = paddingLeft(), pt = paddingTop();
|
|
672
1009
|
y1 += pt; y2 += pt; x1 += pl; x2 += pl;
|
|
673
|
-
var screen = scroller.clientHeight, screentop =
|
|
674
|
-
|
|
675
|
-
|
|
1010
|
+
var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
|
|
1011
|
+
var docBottom = needsScrollbar() || Infinity;
|
|
1012
|
+
var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;
|
|
1013
|
+
if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
|
|
1014
|
+
else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen;
|
|
676
1015
|
|
|
677
1016
|
var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
1017
|
+
var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
|
|
1018
|
+
var atLeft = x1 < gutterw + pl + 10;
|
|
1019
|
+
if (x1 < screenleft + gutterw || atLeft) {
|
|
1020
|
+
if (atLeft) x1 = 0;
|
|
1021
|
+
result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
|
|
1022
|
+
} else if (x2 > screenw + screenleft - 3) {
|
|
1023
|
+
result.scrollLeft = x2 + 10 - screenw;
|
|
682
1024
|
}
|
|
683
|
-
else if (x2 > screenw + screenleft) {
|
|
684
|
-
scroller.scrollLeft = x2 + 10 - screenw;
|
|
685
|
-
scrolled = true;
|
|
686
|
-
if (x2 > code.clientWidth) result = false;
|
|
687
|
-
}
|
|
688
|
-
if (scrolled && options.onScroll) options.onScroll(instance);
|
|
689
1025
|
return result;
|
|
690
1026
|
}
|
|
691
1027
|
|
|
692
|
-
function visibleLines() {
|
|
693
|
-
var lh =
|
|
694
|
-
|
|
695
|
-
|
|
1028
|
+
function visibleLines(scrollTop) {
|
|
1029
|
+
var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
|
|
1030
|
+
var fromHeight = Math.max(0, Math.floor(top / lh));
|
|
1031
|
+
var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
|
|
1032
|
+
return {from: lineAtHeight(doc, fromHeight),
|
|
1033
|
+
to: lineAtHeight(doc, toHeight)};
|
|
696
1034
|
}
|
|
697
1035
|
// Uses a set of changes plus the current scroll position to
|
|
698
1036
|
// determine which DOM updates have to be made, and makes the
|
|
699
1037
|
// updates.
|
|
700
|
-
function updateDisplay(changes) {
|
|
1038
|
+
function updateDisplay(changes, suppressCallback, scrollTop) {
|
|
701
1039
|
if (!scroller.clientWidth) {
|
|
702
|
-
showingFrom = showingTo = 0;
|
|
1040
|
+
showingFrom = showingTo = displayOffset = 0;
|
|
703
1041
|
return;
|
|
704
1042
|
}
|
|
705
|
-
//
|
|
706
|
-
//
|
|
707
|
-
|
|
1043
|
+
// Compute the new visible window
|
|
1044
|
+
// If scrollTop is specified, use that to determine which lines
|
|
1045
|
+
// to render instead of the current scrollbar position.
|
|
1046
|
+
var visible = visibleLines(scrollTop);
|
|
1047
|
+
// Bail out if the visible area is already rendered and nothing changed.
|
|
1048
|
+
if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
|
|
1049
|
+
updateVerticalScroll(scrollTop);
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
|
|
1053
|
+
if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
|
|
1054
|
+
if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
|
|
1055
|
+
|
|
1056
|
+
// Create a range of theoretically intact lines, and punch holes
|
|
1057
|
+
// in that using the change info.
|
|
1058
|
+
var intact = changes === true ? [] :
|
|
1059
|
+
computeIntact([{from: showingFrom, to: showingTo, domStart: 0}], changes);
|
|
1060
|
+
// Clip off the parts that won't be visible
|
|
1061
|
+
var intactLines = 0;
|
|
1062
|
+
for (var i = 0; i < intact.length; ++i) {
|
|
1063
|
+
var range = intact[i];
|
|
1064
|
+
if (range.from < from) {range.domStart += (from - range.from); range.from = from;}
|
|
1065
|
+
if (range.to > to) range.to = to;
|
|
1066
|
+
if (range.from >= range.to) intact.splice(i--, 1);
|
|
1067
|
+
else intactLines += range.to - range.from;
|
|
1068
|
+
}
|
|
1069
|
+
if (intactLines == to - from && from == showingFrom && to == showingTo) {
|
|
1070
|
+
updateVerticalScroll(scrollTop);
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
intact.sort(function(a, b) {return a.domStart - b.domStart;});
|
|
1074
|
+
|
|
1075
|
+
var th = textHeight(), gutterDisplay = gutter.style.display;
|
|
1076
|
+
lineDiv.style.display = "none";
|
|
1077
|
+
patchDisplay(from, to, intact);
|
|
1078
|
+
lineDiv.style.display = gutter.style.display = "";
|
|
1079
|
+
|
|
1080
|
+
var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
|
|
1081
|
+
// This is just a bogus formula that detects when the editor is
|
|
1082
|
+
// resized or the font size changes.
|
|
1083
|
+
if (different) lastSizeC = scroller.clientHeight + th;
|
|
1084
|
+
if (from != showingFrom || to != showingTo && options.onViewportChange)
|
|
1085
|
+
setTimeout(function(){
|
|
1086
|
+
if (options.onViewportChange) options.onViewportChange(instance, from, to);
|
|
1087
|
+
});
|
|
1088
|
+
showingFrom = from; showingTo = to;
|
|
1089
|
+
displayOffset = heightAtLine(doc, from);
|
|
1090
|
+
startWorker(100);
|
|
1091
|
+
|
|
1092
|
+
// Since this is all rather error prone, it is honoured with the
|
|
1093
|
+
// only assertion in the whole file.
|
|
1094
|
+
if (lineDiv.childNodes.length != showingTo - showingFrom)
|
|
1095
|
+
throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
|
|
1096
|
+
" nodes=" + lineDiv.childNodes.length);
|
|
1097
|
+
|
|
1098
|
+
function checkHeights() {
|
|
1099
|
+
var curNode = lineDiv.firstChild, heightChanged = false;
|
|
1100
|
+
doc.iter(showingFrom, showingTo, function(line) {
|
|
1101
|
+
// Work around bizarro IE7 bug where, sometimes, our curNode
|
|
1102
|
+
// is magically replaced with a new node in the DOM, leaving
|
|
1103
|
+
// us with a reference to an orphan (nextSibling-less) node.
|
|
1104
|
+
if (!curNode) return;
|
|
1105
|
+
if (!line.hidden) {
|
|
1106
|
+
var height = Math.round(curNode.offsetHeight / th) || 1;
|
|
1107
|
+
if (line.height != height) {
|
|
1108
|
+
updateLineHeight(line, height);
|
|
1109
|
+
gutterDirty = heightChanged = true;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
curNode = curNode.nextSibling;
|
|
1113
|
+
});
|
|
1114
|
+
return heightChanged;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
if (options.lineWrapping) checkHeights();
|
|
1118
|
+
|
|
1119
|
+
gutter.style.display = gutterDisplay;
|
|
1120
|
+
if (different || gutterDirty) {
|
|
1121
|
+
// If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
|
|
1122
|
+
updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
|
|
1123
|
+
}
|
|
1124
|
+
updateVerticalScroll(scrollTop);
|
|
1125
|
+
updateSelection();
|
|
1126
|
+
if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
|
|
1127
|
+
return true;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
function computeIntact(intact, changes) {
|
|
708
1131
|
for (var i = 0, l = changes.length || 0; i < l; ++i) {
|
|
709
1132
|
var change = changes[i], intact2 = [], diff = change.diff || 0;
|
|
710
1133
|
for (var j = 0, l2 = intact.length; j < l2; ++j) {
|
|
711
1134
|
var range = intact[j];
|
|
712
|
-
if (change.to <= range.from)
|
|
713
|
-
intact2.push({from: range.from + diff, to: range.to + diff,
|
|
714
|
-
|
|
1135
|
+
if (change.to <= range.from && change.diff)
|
|
1136
|
+
intact2.push({from: range.from + diff, to: range.to + diff,
|
|
1137
|
+
domStart: range.domStart});
|
|
1138
|
+
else if (change.to <= range.from || change.from >= range.to)
|
|
715
1139
|
intact2.push(range);
|
|
716
1140
|
else {
|
|
717
1141
|
if (change.from > range.from)
|
|
718
|
-
intact2.push({from: range.from, to: change.from, domStart: range.domStart})
|
|
1142
|
+
intact2.push({from: range.from, to: change.from, domStart: range.domStart});
|
|
719
1143
|
if (change.to < range.to)
|
|
720
1144
|
intact2.push({from: change.to + diff, to: range.to + diff,
|
|
721
1145
|
domStart: range.domStart + (change.to - range.from)});
|
|
@@ -723,163 +1147,132 @@ var CodeMirror = (function() {
|
|
|
723
1147
|
}
|
|
724
1148
|
intact = intact2;
|
|
725
1149
|
}
|
|
726
|
-
|
|
727
|
-
// Then, determine which lines we'd want to see, and which
|
|
728
|
-
// updates have to be made to get there.
|
|
729
|
-
var visible = visibleLines();
|
|
730
|
-
var from = Math.min(showingFrom, Math.max(visible.from - 3, 0)),
|
|
731
|
-
to = Math.min(lines.length, Math.max(showingTo, visible.to + 3)),
|
|
732
|
-
updates = [], domPos = 0, domEnd = showingTo - showingFrom, pos = from, changedLines = 0;
|
|
733
|
-
|
|
734
|
-
for (var i = 0, l = intact.length; i < l; ++i) {
|
|
735
|
-
var range = intact[i];
|
|
736
|
-
if (range.to <= from) continue;
|
|
737
|
-
if (range.from >= to) break;
|
|
738
|
-
if (range.domStart > domPos || range.from > pos) {
|
|
739
|
-
updates.push({from: pos, to: range.from, domSize: range.domStart - domPos, domStart: domPos});
|
|
740
|
-
changedLines += range.from - pos;
|
|
741
|
-
}
|
|
742
|
-
pos = range.to;
|
|
743
|
-
domPos = range.domStart + (range.to - range.from);
|
|
744
|
-
}
|
|
745
|
-
if (domPos != domEnd || pos != to) {
|
|
746
|
-
changedLines += Math.abs(to - pos);
|
|
747
|
-
updates.push({from: pos, to: to, domSize: domEnd - domPos, domStart: domPos});
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
if (!updates.length) return;
|
|
751
|
-
lineDiv.style.display = "none";
|
|
752
|
-
// If more than 30% of the screen needs update, just do a full
|
|
753
|
-
// redraw (which is quicker than patching)
|
|
754
|
-
if (changedLines > (visible.to - visible.from) * .3)
|
|
755
|
-
refreshDisplay(from = Math.max(visible.from - 10, 0), to = Math.min(visible.to + 7, lines.length));
|
|
756
|
-
// Otherwise, only update the stuff that needs updating.
|
|
757
|
-
else
|
|
758
|
-
patchDisplay(updates);
|
|
759
|
-
lineDiv.style.display = "";
|
|
760
|
-
|
|
761
|
-
// Position the mover div to align with the lines it's supposed
|
|
762
|
-
// to be showing (which will cover the visible display)
|
|
763
|
-
var different = from != showingFrom || to != showingTo || lastHeight != scroller.clientHeight;
|
|
764
|
-
showingFrom = from; showingTo = to;
|
|
765
|
-
mover.style.top = (from * lineHeight()) + "px";
|
|
766
|
-
if (different) {
|
|
767
|
-
lastHeight = scroller.clientHeight;
|
|
768
|
-
code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
|
|
769
|
-
updateGutter();
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
if (maxWidth == null) maxWidth = stringWidth(maxLine);
|
|
773
|
-
if (maxWidth > scroller.clientWidth) {
|
|
774
|
-
lineSpace.style.width = maxWidth + "px";
|
|
775
|
-
// Needed to prevent odd wrapping/hiding of widgets placed in here.
|
|
776
|
-
code.style.width = "";
|
|
777
|
-
code.style.width = scroller.scrollWidth + "px";
|
|
778
|
-
} else {
|
|
779
|
-
lineSpace.style.width = code.style.width = "";
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// Since this is all rather error prone, it is honoured with the
|
|
783
|
-
// only assertion in the whole file.
|
|
784
|
-
if (lineDiv.childNodes.length != showingTo - showingFrom)
|
|
785
|
-
throw new Error("BAD PATCH! " + JSON.stringify(updates) + " size=" + (showingTo - showingFrom) +
|
|
786
|
-
" nodes=" + lineDiv.childNodes.length);
|
|
787
|
-
updateCursor();
|
|
1150
|
+
return intact;
|
|
788
1151
|
}
|
|
789
1152
|
|
|
790
|
-
function
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
lineDiv.innerHTML = html.join("");
|
|
805
|
-
}
|
|
806
|
-
function patchDisplay(updates) {
|
|
807
|
-
// Slightly different algorithm for IE (badInnerHTML), since
|
|
808
|
-
// there .innerHTML on PRE nodes is dumb, and discards
|
|
809
|
-
// whitespace.
|
|
810
|
-
var sfrom = sel.from.line, sto = sel.to.line, off = 0,
|
|
811
|
-
scratch = badInnerHTML && targetDocument.createElement("div");
|
|
812
|
-
for (var i = 0, e = updates.length; i < e; ++i) {
|
|
813
|
-
var rec = updates[i];
|
|
814
|
-
var extra = (rec.to - rec.from) - rec.domSize;
|
|
815
|
-
var nodeAfter = lineDiv.childNodes[rec.domStart + rec.domSize + off] || null;
|
|
816
|
-
if (badInnerHTML)
|
|
817
|
-
for (var j = Math.max(-extra, rec.domSize); j > 0; --j)
|
|
818
|
-
lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
|
|
819
|
-
else if (extra) {
|
|
820
|
-
for (var j = Math.max(0, extra); j > 0; --j)
|
|
821
|
-
lineDiv.insertBefore(targetDocument.createElement("pre"), nodeAfter);
|
|
822
|
-
for (var j = Math.max(0, -extra); j > 0; --j)
|
|
823
|
-
lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
|
|
1153
|
+
function patchDisplay(from, to, intact) {
|
|
1154
|
+
function killNode(node) {
|
|
1155
|
+
var tmp = node.nextSibling;
|
|
1156
|
+
node.parentNode.removeChild(node);
|
|
1157
|
+
return tmp;
|
|
1158
|
+
}
|
|
1159
|
+
// The first pass removes the DOM nodes that aren't intact.
|
|
1160
|
+
if (!intact.length) removeChildren(lineDiv);
|
|
1161
|
+
else {
|
|
1162
|
+
var domPos = 0, curNode = lineDiv.firstChild, n;
|
|
1163
|
+
for (var i = 0; i < intact.length; ++i) {
|
|
1164
|
+
var cur = intact[i];
|
|
1165
|
+
while (cur.domStart > domPos) {curNode = killNode(curNode); domPos++;}
|
|
1166
|
+
for (var j = 0, e = cur.to - cur.from; j < e; ++j) {curNode = curNode.nextSibling; domPos++;}
|
|
824
1167
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
|
|
834
|
-
else {inSel = true; ch1 = sel.from.ch;}
|
|
835
|
-
}
|
|
836
|
-
if (badInnerHTML) {
|
|
837
|
-
scratch.innerHTML = lines[j].getHTML(ch1, ch2, true);
|
|
838
|
-
lineDiv.insertBefore(scratch.firstChild, nodeAfter);
|
|
839
|
-
}
|
|
1168
|
+
while (curNode) curNode = killNode(curNode);
|
|
1169
|
+
}
|
|
1170
|
+
// This pass fills in the lines that actually changed.
|
|
1171
|
+
var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
|
|
1172
|
+
doc.iter(from, to, function(line) {
|
|
1173
|
+
if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
|
|
1174
|
+
if (!nextIntact || nextIntact.from > j) {
|
|
1175
|
+
if (line.hidden) var lineElement = elt("pre");
|
|
840
1176
|
else {
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1177
|
+
var lineElement = lineContent(line);
|
|
1178
|
+
if (line.className) lineElement.className = line.className;
|
|
1179
|
+
// Kludge to make sure the styled element lies behind the selection (by z-index)
|
|
1180
|
+
if (line.bgClassName) {
|
|
1181
|
+
var pre = elt("pre", "\u00a0", line.bgClassName, "position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2");
|
|
1182
|
+
lineElement = elt("div", [pre, lineElement], null, "position: relative");
|
|
1183
|
+
}
|
|
844
1184
|
}
|
|
1185
|
+
lineDiv.insertBefore(lineElement, curNode);
|
|
1186
|
+
} else {
|
|
1187
|
+
curNode = curNode.nextSibling;
|
|
845
1188
|
}
|
|
846
|
-
|
|
847
|
-
}
|
|
1189
|
+
++j;
|
|
1190
|
+
});
|
|
848
1191
|
}
|
|
849
1192
|
|
|
850
1193
|
function updateGutter() {
|
|
851
1194
|
if (!options.gutter && !options.lineNumbers) return;
|
|
852
1195
|
var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
|
|
853
1196
|
gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
|
|
854
|
-
var
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1197
|
+
var fragment = document.createDocumentFragment(), i = showingFrom, normalNode;
|
|
1198
|
+
doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
|
|
1199
|
+
if (line.hidden) {
|
|
1200
|
+
fragment.appendChild(elt("pre"));
|
|
1201
|
+
} else {
|
|
1202
|
+
var marker = line.gutterMarker;
|
|
1203
|
+
var text = options.lineNumbers ? options.lineNumberFormatter(i + options.firstLineNumber) : null;
|
|
1204
|
+
if (marker && marker.text)
|
|
1205
|
+
text = marker.text.replace("%N%", text != null ? text : "");
|
|
1206
|
+
else if (text == null)
|
|
1207
|
+
text = "\u00a0";
|
|
1208
|
+
var markerElement = fragment.appendChild(elt("pre", null, marker && marker.style));
|
|
1209
|
+
markerElement.innerHTML = text;
|
|
1210
|
+
for (var j = 1; j < line.height; ++j) {
|
|
1211
|
+
markerElement.appendChild(elt("br"));
|
|
1212
|
+
markerElement.appendChild(document.createTextNode("\u00a0"));
|
|
1213
|
+
}
|
|
1214
|
+
if (!marker) normalNode = i;
|
|
1215
|
+
}
|
|
1216
|
+
++i;
|
|
1217
|
+
});
|
|
864
1218
|
gutter.style.display = "none";
|
|
865
|
-
gutterText
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1219
|
+
removeChildrenAndAdd(gutterText, fragment);
|
|
1220
|
+
// Make sure scrolling doesn't cause number gutter size to pop
|
|
1221
|
+
if (normalNode != null && options.lineNumbers) {
|
|
1222
|
+
var node = gutterText.childNodes[normalNode - showingFrom];
|
|
1223
|
+
var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
|
|
1224
|
+
while (val.length + pad.length < minwidth) pad += "\u00a0";
|
|
1225
|
+
if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
|
|
1226
|
+
}
|
|
869
1227
|
gutter.style.display = "";
|
|
1228
|
+
var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2;
|
|
870
1229
|
lineSpace.style.marginLeft = gutter.offsetWidth + "px";
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1230
|
+
gutterDirty = false;
|
|
1231
|
+
return resized;
|
|
1232
|
+
}
|
|
1233
|
+
function updateSelection() {
|
|
1234
|
+
var collapsed = posEq(sel.from, sel.to);
|
|
1235
|
+
var fromPos = localCoords(sel.from, true);
|
|
1236
|
+
var toPos = collapsed ? fromPos : localCoords(sel.to, true);
|
|
1237
|
+
var headPos = sel.inverted ? fromPos : toPos, th = textHeight();
|
|
1238
|
+
var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv);
|
|
1239
|
+
inputDiv.style.top = Math.max(0, Math.min(scroller.offsetHeight, headPos.y + lineOff.top - wrapOff.top)) + "px";
|
|
1240
|
+
inputDiv.style.left = Math.max(0, Math.min(scroller.offsetWidth, headPos.x + lineOff.left - wrapOff.left)) + "px";
|
|
1241
|
+
if (collapsed) {
|
|
1242
|
+
cursor.style.top = headPos.y + "px";
|
|
1243
|
+
cursor.style.left = (options.lineWrapping ? Math.min(headPos.x, lineSpace.offsetWidth) : headPos.x) + "px";
|
|
878
1244
|
cursor.style.display = "";
|
|
1245
|
+
selectionDiv.style.display = "none";
|
|
1246
|
+
} else {
|
|
1247
|
+
var sameLine = fromPos.y == toPos.y, fragment = document.createDocumentFragment();
|
|
1248
|
+
var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
|
|
1249
|
+
var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
|
|
1250
|
+
var add = function(left, top, right, height) {
|
|
1251
|
+
var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
|
|
1252
|
+
: "right: " + right + "px";
|
|
1253
|
+
fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
|
|
1254
|
+
"px; top: " + top + "px; " + rstyle + "; height: " + height + "px"));
|
|
1255
|
+
};
|
|
1256
|
+
if (sel.from.ch && fromPos.y >= 0) {
|
|
1257
|
+
var right = sameLine ? clientWidth - toPos.x : 0;
|
|
1258
|
+
add(fromPos.x, fromPos.y, right, th);
|
|
1259
|
+
}
|
|
1260
|
+
var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
|
|
1261
|
+
var middleHeight = Math.min(toPos.y, clientHeight) - middleStart;
|
|
1262
|
+
if (middleHeight > 0.2 * th)
|
|
1263
|
+
add(0, middleStart, 0, middleHeight);
|
|
1264
|
+
if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th)
|
|
1265
|
+
add(0, toPos.y, clientWidth - toPos.x, th);
|
|
1266
|
+
removeChildrenAndAdd(selectionDiv, fragment);
|
|
1267
|
+
cursor.style.display = "none";
|
|
1268
|
+
selectionDiv.style.display = "";
|
|
879
1269
|
}
|
|
880
|
-
else cursor.style.display = "none";
|
|
881
1270
|
}
|
|
882
1271
|
|
|
1272
|
+
function setShift(val) {
|
|
1273
|
+
if (val) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
|
|
1274
|
+
else shiftSelecting = null;
|
|
1275
|
+
}
|
|
883
1276
|
function setSelectionUser(from, to) {
|
|
884
1277
|
var sh = shiftSelecting && clipPos(shiftSelecting);
|
|
885
1278
|
if (sh) {
|
|
@@ -887,284 +1280,469 @@ var CodeMirror = (function() {
|
|
|
887
1280
|
else if (posLess(to, sh)) to = sh;
|
|
888
1281
|
}
|
|
889
1282
|
setSelection(from, to);
|
|
1283
|
+
userSelChange = true;
|
|
890
1284
|
}
|
|
891
1285
|
// Update the selection. Last two args are only used by
|
|
892
1286
|
// updateLines, since they have to be expressed in the line
|
|
893
1287
|
// numbers before the update.
|
|
894
1288
|
function setSelection(from, to, oldFrom, oldTo) {
|
|
1289
|
+
goalColumn = null;
|
|
1290
|
+
if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
|
|
895
1291
|
if (posEq(sel.from, from) && posEq(sel.to, to)) return;
|
|
896
1292
|
if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
|
|
897
1293
|
|
|
1294
|
+
// Skip over hidden lines.
|
|
1295
|
+
if (from.line != oldFrom) {
|
|
1296
|
+
var from1 = skipHidden(from, oldFrom, sel.from.ch);
|
|
1297
|
+
// If there is no non-hidden line left, force visibility on current line
|
|
1298
|
+
if (!from1) setLineHidden(from.line, false);
|
|
1299
|
+
else from = from1;
|
|
1300
|
+
}
|
|
1301
|
+
if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
|
|
1302
|
+
|
|
898
1303
|
if (posEq(from, to)) sel.inverted = false;
|
|
899
1304
|
else if (posEq(from, sel.to)) sel.inverted = false;
|
|
900
1305
|
else if (posEq(to, sel.from)) sel.inverted = true;
|
|
901
1306
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
else {
|
|
914
|
-
if (!posEq(from, sel.from)) {
|
|
915
|
-
if (from.line < oldFrom)
|
|
916
|
-
changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1});
|
|
917
|
-
else
|
|
918
|
-
changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1});
|
|
919
|
-
}
|
|
920
|
-
if (!posEq(to, sel.to)) {
|
|
921
|
-
if (to.line < oldTo)
|
|
922
|
-
changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1});
|
|
923
|
-
else
|
|
924
|
-
changes.push({from: Math.max(from.line, oldTo), to: to.line + 1});
|
|
1307
|
+
if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
|
|
1308
|
+
var head = sel.inverted ? from : to;
|
|
1309
|
+
if (head.line != sel.from.line && sel.from.line < doc.size) {
|
|
1310
|
+
var oldLine = getLine(sel.from.line);
|
|
1311
|
+
if (/^\s+$/.test(oldLine.text))
|
|
1312
|
+
setTimeout(operation(function() {
|
|
1313
|
+
if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
|
|
1314
|
+
var no = lineNo(oldLine);
|
|
1315
|
+
replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
|
|
1316
|
+
}
|
|
1317
|
+
}, 10));
|
|
925
1318
|
}
|
|
926
1319
|
}
|
|
1320
|
+
|
|
927
1321
|
sel.from = from; sel.to = to;
|
|
928
1322
|
selectionChanged = true;
|
|
929
1323
|
}
|
|
1324
|
+
function skipHidden(pos, oldLine, oldCh) {
|
|
1325
|
+
function getNonHidden(dir) {
|
|
1326
|
+
var lNo = pos.line + dir, end = dir == 1 ? doc.size : -1;
|
|
1327
|
+
while (lNo != end) {
|
|
1328
|
+
var line = getLine(lNo);
|
|
1329
|
+
if (!line.hidden) {
|
|
1330
|
+
var ch = pos.ch;
|
|
1331
|
+
if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
|
|
1332
|
+
return {line: lNo, ch: ch};
|
|
1333
|
+
}
|
|
1334
|
+
lNo += dir;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
var line = getLine(pos.line);
|
|
1338
|
+
var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
|
|
1339
|
+
if (!line.hidden) return pos;
|
|
1340
|
+
if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
|
|
1341
|
+
else return getNonHidden(-1) || getNonHidden(1);
|
|
1342
|
+
}
|
|
930
1343
|
function setCursor(line, ch, user) {
|
|
931
1344
|
var pos = clipPos({line: line, ch: ch || 0});
|
|
932
1345
|
(user ? setSelectionUser : setSelection)(pos, pos);
|
|
933
1346
|
}
|
|
934
1347
|
|
|
935
|
-
function clipLine(n) {return Math.max(0, Math.min(n,
|
|
1348
|
+
function clipLine(n) {return Math.max(0, Math.min(n, doc.size-1));}
|
|
936
1349
|
function clipPos(pos) {
|
|
937
1350
|
if (pos.line < 0) return {line: 0, ch: 0};
|
|
938
|
-
if (pos.line >=
|
|
939
|
-
var ch = pos.ch, linelen =
|
|
1351
|
+
if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc.size-1).text.length};
|
|
1352
|
+
var ch = pos.ch, linelen = getLine(pos.line).text.length;
|
|
940
1353
|
if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
|
|
941
1354
|
else if (ch < 0) return {line: pos.line, ch: 0};
|
|
942
1355
|
else return pos;
|
|
943
1356
|
}
|
|
944
1357
|
|
|
945
|
-
function
|
|
946
|
-
var
|
|
947
|
-
|
|
1358
|
+
function findPosH(dir, unit) {
|
|
1359
|
+
var end = sel.inverted ? sel.from : sel.to, line = end.line, ch = end.ch;
|
|
1360
|
+
var lineObj = getLine(line);
|
|
1361
|
+
function findNextLine() {
|
|
1362
|
+
for (var l = line + dir, e = dir < 0 ? -1 : doc.size; l != e; l += dir) {
|
|
1363
|
+
var lo = getLine(l);
|
|
1364
|
+
if (!lo.hidden) { line = l; lineObj = lo; return true; }
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
function moveOnce(boundToLine) {
|
|
1368
|
+
if (ch == (dir < 0 ? 0 : lineObj.text.length)) {
|
|
1369
|
+
if (!boundToLine && findNextLine()) ch = dir < 0 ? lineObj.text.length : 0;
|
|
1370
|
+
else return false;
|
|
1371
|
+
} else ch += dir;
|
|
1372
|
+
return true;
|
|
1373
|
+
}
|
|
1374
|
+
if (unit == "char") moveOnce();
|
|
1375
|
+
else if (unit == "column") moveOnce(true);
|
|
1376
|
+
else if (unit == "word") {
|
|
1377
|
+
var sawWord = false;
|
|
1378
|
+
for (;;) {
|
|
1379
|
+
if (dir < 0) if (!moveOnce()) break;
|
|
1380
|
+
if (isWordChar(lineObj.text.charAt(ch))) sawWord = true;
|
|
1381
|
+
else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;}
|
|
1382
|
+
if (dir > 0) if (!moveOnce()) break;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
return {line: line, ch: ch};
|
|
948
1386
|
}
|
|
949
|
-
function
|
|
950
|
-
var pos =
|
|
951
|
-
|
|
1387
|
+
function moveH(dir, unit) {
|
|
1388
|
+
var pos = dir < 0 ? sel.from : sel.to;
|
|
1389
|
+
if (shiftSelecting || posEq(sel.from, sel.to)) pos = findPosH(dir, unit);
|
|
1390
|
+
setCursor(pos.line, pos.ch, true);
|
|
952
1391
|
}
|
|
953
|
-
function
|
|
954
|
-
|
|
955
|
-
|
|
1392
|
+
function deleteH(dir, unit) {
|
|
1393
|
+
if (!posEq(sel.from, sel.to)) replaceRange("", sel.from, sel.to);
|
|
1394
|
+
else if (dir < 0) replaceRange("", findPosH(dir, unit), sel.to);
|
|
1395
|
+
else replaceRange("", sel.from, findPosH(dir, unit));
|
|
1396
|
+
userSelChange = true;
|
|
956
1397
|
}
|
|
957
|
-
function
|
|
958
|
-
var
|
|
1398
|
+
function moveV(dir, unit) {
|
|
1399
|
+
var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true);
|
|
1400
|
+
if (goalColumn != null) pos.x = goalColumn;
|
|
1401
|
+
if (unit == "page") {
|
|
1402
|
+
var screen = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
|
|
1403
|
+
var target = coordsChar(pos.x, pos.y + screen * dir);
|
|
1404
|
+
} else if (unit == "line") {
|
|
1405
|
+
var th = textHeight();
|
|
1406
|
+
var target = coordsChar(pos.x, pos.y + .5 * th + dir * th);
|
|
1407
|
+
}
|
|
1408
|
+
if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
|
|
1409
|
+
setCursor(target.line, target.ch, true);
|
|
1410
|
+
goalColumn = pos.x;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
function findWordAt(pos) {
|
|
1414
|
+
var line = getLine(pos.line).text;
|
|
959
1415
|
var start = pos.ch, end = pos.ch;
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1416
|
+
if (line) {
|
|
1417
|
+
if (pos.after === false || end == line.length) --start; else ++end;
|
|
1418
|
+
var startChar = line.charAt(start);
|
|
1419
|
+
var check = isWordChar(startChar) ? isWordChar :
|
|
1420
|
+
/\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} :
|
|
1421
|
+
function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
|
|
1422
|
+
while (start > 0 && check(line.charAt(start - 1))) --start;
|
|
1423
|
+
while (end < line.length && check(line.charAt(end))) ++end;
|
|
1424
|
+
}
|
|
1425
|
+
return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}};
|
|
963
1426
|
}
|
|
964
1427
|
function selectLine(line) {
|
|
965
|
-
setSelectionUser({line: line, ch: 0}, {line: line, ch:
|
|
1428
|
+
setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
|
|
966
1429
|
}
|
|
967
|
-
function
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
function handleTab(shift) {
|
|
973
|
-
function indentSelected(mode) {
|
|
974
|
-
if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
|
|
975
|
-
var e = sel.to.line - (sel.to.ch ? 0 : 1);
|
|
976
|
-
for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
|
|
977
|
-
}
|
|
978
|
-
shiftSelecting = null;
|
|
979
|
-
switch (options.tabMode) {
|
|
980
|
-
case "default":
|
|
981
|
-
return false;
|
|
982
|
-
case "indent":
|
|
983
|
-
indentSelected("smart");
|
|
984
|
-
break;
|
|
985
|
-
case "classic":
|
|
986
|
-
if (posEq(sel.from, sel.to)) {
|
|
987
|
-
if (shift) indentLine(sel.from.line, "smart");
|
|
988
|
-
else replaceSelection("\t", "end");
|
|
989
|
-
break;
|
|
990
|
-
}
|
|
991
|
-
case "shift":
|
|
992
|
-
indentSelected(shift ? "subtract" : "add");
|
|
993
|
-
break;
|
|
994
|
-
}
|
|
995
|
-
return true;
|
|
1430
|
+
function indentSelected(mode) {
|
|
1431
|
+
if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
|
|
1432
|
+
var e = sel.to.line - (sel.to.ch ? 0 : 1);
|
|
1433
|
+
for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
|
|
996
1434
|
}
|
|
997
1435
|
|
|
998
1436
|
function indentLine(n, how) {
|
|
1437
|
+
if (!how) how = "add";
|
|
999
1438
|
if (how == "smart") {
|
|
1000
1439
|
if (!mode.indent) how = "prev";
|
|
1001
1440
|
else var state = getStateBefore(n);
|
|
1002
1441
|
}
|
|
1003
1442
|
|
|
1004
|
-
var line =
|
|
1443
|
+
var line = getLine(n), curSpace = line.indentation(options.tabSize),
|
|
1444
|
+
curSpaceString = line.text.match(/^\s*/)[0], indentation;
|
|
1445
|
+
if (how == "smart") {
|
|
1446
|
+
indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
|
1447
|
+
if (indentation == Pass) how = "prev";
|
|
1448
|
+
}
|
|
1005
1449
|
if (how == "prev") {
|
|
1006
|
-
if (n) indentation =
|
|
1450
|
+
if (n) indentation = getLine(n-1).indentation(options.tabSize);
|
|
1007
1451
|
else indentation = 0;
|
|
1008
1452
|
}
|
|
1009
|
-
else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length));
|
|
1010
1453
|
else if (how == "add") indentation = curSpace + options.indentUnit;
|
|
1011
1454
|
else if (how == "subtract") indentation = curSpace - options.indentUnit;
|
|
1012
1455
|
indentation = Math.max(0, indentation);
|
|
1013
1456
|
var diff = indentation - curSpace;
|
|
1014
1457
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
var
|
|
1018
|
-
|
|
1019
|
-
else {
|
|
1020
|
-
var indentString = "", pos = 0;
|
|
1021
|
-
if (options.indentWithTabs)
|
|
1022
|
-
for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
|
|
1023
|
-
while (pos < indentation) {++pos; indentString += " ";}
|
|
1024
|
-
}
|
|
1458
|
+
var indentString = "", pos = 0;
|
|
1459
|
+
if (options.indentWithTabs)
|
|
1460
|
+
for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
|
|
1461
|
+
if (pos < indentation) indentString += spaceStr(indentation - pos);
|
|
1025
1462
|
|
|
1026
|
-
|
|
1463
|
+
if (indentString != curSpaceString)
|
|
1464
|
+
replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
|
|
1027
1465
|
}
|
|
1028
1466
|
|
|
1029
1467
|
function loadMode() {
|
|
1030
1468
|
mode = CodeMirror.getMode(options, options.mode);
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
startWorker();
|
|
1469
|
+
doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
|
|
1470
|
+
frontier = 0;
|
|
1471
|
+
startWorker(100);
|
|
1035
1472
|
}
|
|
1036
1473
|
function gutterChanged() {
|
|
1037
1474
|
var visible = options.gutter || options.lineNumbers;
|
|
1038
1475
|
gutter.style.display = visible ? "" : "none";
|
|
1039
|
-
if (visible)
|
|
1476
|
+
if (visible) gutterDirty = true;
|
|
1040
1477
|
else lineDiv.parentNode.style.marginLeft = 0;
|
|
1041
1478
|
}
|
|
1479
|
+
function wrappingChanged(from, to) {
|
|
1480
|
+
if (options.lineWrapping) {
|
|
1481
|
+
wrapper.className += " CodeMirror-wrap";
|
|
1482
|
+
var perLine = scroller.clientWidth / charWidth() - 3;
|
|
1483
|
+
doc.iter(0, doc.size, function(line) {
|
|
1484
|
+
if (line.hidden) return;
|
|
1485
|
+
var guess = Math.ceil(line.text.length / perLine) || 1;
|
|
1486
|
+
if (guess != 1) updateLineHeight(line, guess);
|
|
1487
|
+
});
|
|
1488
|
+
lineSpace.style.minWidth = widthForcer.style.left = "";
|
|
1489
|
+
} else {
|
|
1490
|
+
wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
|
|
1491
|
+
computeMaxLength();
|
|
1492
|
+
doc.iter(0, doc.size, function(line) {
|
|
1493
|
+
if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
changes.push({from: 0, to: doc.size});
|
|
1497
|
+
}
|
|
1498
|
+
function themeChanged() {
|
|
1499
|
+
scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
|
|
1500
|
+
options.theme.replace(/(^|\s)\s*/g, " cm-s-");
|
|
1501
|
+
}
|
|
1502
|
+
function keyMapChanged() {
|
|
1503
|
+
var style = keyMap[options.keyMap].style;
|
|
1504
|
+
wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
|
|
1505
|
+
(style ? " cm-keymap-" + style : "");
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
function TextMarker(type, style) { this.lines = []; this.type = type; if (style) this.style = style; }
|
|
1509
|
+
TextMarker.prototype.clear = operation(function() {
|
|
1510
|
+
var min = Infinity, max = -Infinity;
|
|
1511
|
+
for (var i = 0; i < this.lines.length; ++i) {
|
|
1512
|
+
var line = this.lines[i];
|
|
1513
|
+
var span = getMarkedSpanFor(line.markedSpans, this, true);
|
|
1514
|
+
if (span.from != null || span.to != null) {
|
|
1515
|
+
var lineN = lineNo(line);
|
|
1516
|
+
min = Math.min(min, lineN); max = Math.max(max, lineN);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
if (min != Infinity)
|
|
1520
|
+
changes.push({from: min, to: max + 1});
|
|
1521
|
+
this.lines.length = 0;
|
|
1522
|
+
});
|
|
1523
|
+
TextMarker.prototype.find = function() {
|
|
1524
|
+
var from, to;
|
|
1525
|
+
for (var i = 0; i < this.lines.length; ++i) {
|
|
1526
|
+
var line = this.lines[i];
|
|
1527
|
+
var span = getMarkedSpanFor(line.markedSpans, this);
|
|
1528
|
+
if (span.from != null || span.to != null) {
|
|
1529
|
+
var found = lineNo(line);
|
|
1530
|
+
if (span.from != null) from = {line: found, ch: span.from};
|
|
1531
|
+
if (span.to != null) to = {line: found, ch: span.to};
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
if (this.type == "bookmark") return from;
|
|
1535
|
+
return from && {from: from, to: to};
|
|
1536
|
+
};
|
|
1042
1537
|
|
|
1043
|
-
function markText(from, to, className) {
|
|
1538
|
+
function markText(from, to, className, options) {
|
|
1044
1539
|
from = clipPos(from); to = clipPos(to);
|
|
1045
|
-
var
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1540
|
+
var marker = new TextMarker("range", className);
|
|
1541
|
+
if (options) for (var opt in options) if (options.hasOwnProperty(opt))
|
|
1542
|
+
marker[opt] = options[opt];
|
|
1543
|
+
var curLine = from.line;
|
|
1544
|
+
doc.iter(curLine, to.line + 1, function(line) {
|
|
1545
|
+
var span = {from: curLine == from.line ? from.ch : null,
|
|
1546
|
+
to: curLine == to.line ? to.ch : null,
|
|
1547
|
+
marker: marker};
|
|
1548
|
+
(line.markedSpans || (line.markedSpans = [])).push(span);
|
|
1549
|
+
marker.lines.push(line);
|
|
1550
|
+
++curLine;
|
|
1551
|
+
});
|
|
1552
|
+
changes.push({from: from.line, to: to.line + 1});
|
|
1553
|
+
return marker;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
function setBookmark(pos) {
|
|
1557
|
+
pos = clipPos(pos);
|
|
1558
|
+
var marker = new TextMarker("bookmark"), line = getLine(pos.line);
|
|
1559
|
+
var span = {from: pos.ch, to: pos.ch, marker: marker};
|
|
1560
|
+
(line.markedSpans || (line.markedSpans = [])).push(span);
|
|
1561
|
+
marker.lines.push(line);
|
|
1562
|
+
return marker;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
function findMarksAt(pos) {
|
|
1566
|
+
pos = clipPos(pos);
|
|
1567
|
+
var markers = [], spans = getLine(pos.line).markedSpans;
|
|
1568
|
+
if (spans) for (var i = 0; i < spans.length; ++i) {
|
|
1569
|
+
var span = spans[i];
|
|
1570
|
+
if ((span.from == null || span.from <= pos.ch) &&
|
|
1571
|
+
(span.to == null || span.to >= pos.ch))
|
|
1572
|
+
markers.push(span.marker);
|
|
1057
1573
|
}
|
|
1058
|
-
|
|
1059
|
-
return function() {
|
|
1060
|
-
var start, end;
|
|
1061
|
-
for (var i = 0; i < accum.length; ++i) {
|
|
1062
|
-
var mark = accum[i], found = indexOf(lines, mark.line);
|
|
1063
|
-
mark.line.removeMark(mark);
|
|
1064
|
-
if (found > -1) {
|
|
1065
|
-
if (start == null) start = found;
|
|
1066
|
-
end = found;
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
if (start != null) changes.push({from: start, to: end + 1});
|
|
1070
|
-
};
|
|
1574
|
+
return markers;
|
|
1071
1575
|
}
|
|
1072
1576
|
|
|
1073
1577
|
function addGutterMarker(line, text, className) {
|
|
1074
|
-
if (typeof line == "number") line =
|
|
1578
|
+
if (typeof line == "number") line = getLine(clipLine(line));
|
|
1075
1579
|
line.gutterMarker = {text: text, style: className};
|
|
1076
|
-
|
|
1580
|
+
gutterDirty = true;
|
|
1077
1581
|
return line;
|
|
1078
1582
|
}
|
|
1079
1583
|
function removeGutterMarker(line) {
|
|
1080
|
-
if (typeof line == "number") line =
|
|
1584
|
+
if (typeof line == "number") line = getLine(clipLine(line));
|
|
1081
1585
|
line.gutterMarker = null;
|
|
1082
|
-
|
|
1586
|
+
gutterDirty = true;
|
|
1083
1587
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
}
|
|
1093
|
-
if (line.className != className) {
|
|
1094
|
-
line.className = className;
|
|
1095
|
-
changes.push({from: no, to: no + 1});
|
|
1096
|
-
}
|
|
1588
|
+
|
|
1589
|
+
function changeLine(handle, op) {
|
|
1590
|
+
var no = handle, line = handle;
|
|
1591
|
+
if (typeof handle == "number") line = getLine(clipLine(handle));
|
|
1592
|
+
else no = lineNo(handle);
|
|
1593
|
+
if (no == null) return null;
|
|
1594
|
+
if (op(line, no)) changes.push({from: no, to: no + 1});
|
|
1595
|
+
else return null;
|
|
1097
1596
|
return line;
|
|
1098
1597
|
}
|
|
1598
|
+
function setLineClass(handle, className, bgClassName) {
|
|
1599
|
+
return changeLine(handle, function(line) {
|
|
1600
|
+
if (line.className != className || line.bgClassName != bgClassName) {
|
|
1601
|
+
line.className = className;
|
|
1602
|
+
line.bgClassName = bgClassName;
|
|
1603
|
+
return true;
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1606
|
+
}
|
|
1607
|
+
function setLineHidden(handle, hidden) {
|
|
1608
|
+
return changeLine(handle, function(line, no) {
|
|
1609
|
+
if (line.hidden != hidden) {
|
|
1610
|
+
line.hidden = hidden;
|
|
1611
|
+
if (!options.lineWrapping) {
|
|
1612
|
+
if (hidden && line.text.length == maxLine.text.length) {
|
|
1613
|
+
updateMaxLine = true;
|
|
1614
|
+
} else if (!hidden && line.text.length > maxLine.text.length) {
|
|
1615
|
+
maxLine = line; updateMaxLine = false;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
updateLineHeight(line, hidden ? 0 : 1);
|
|
1619
|
+
var fline = sel.from.line, tline = sel.to.line;
|
|
1620
|
+
if (hidden && (fline == no || tline == no)) {
|
|
1621
|
+
var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
|
|
1622
|
+
var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
|
|
1623
|
+
// Can't hide the last visible line, we'd have no place to put the cursor
|
|
1624
|
+
if (!to) return;
|
|
1625
|
+
setSelection(from, to);
|
|
1626
|
+
}
|
|
1627
|
+
return (gutterDirty = true);
|
|
1628
|
+
}
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1099
1631
|
|
|
1100
1632
|
function lineInfo(line) {
|
|
1101
1633
|
if (typeof line == "number") {
|
|
1634
|
+
if (!isLine(line)) return null;
|
|
1102
1635
|
var n = line;
|
|
1103
|
-
line =
|
|
1636
|
+
line = getLine(line);
|
|
1104
1637
|
if (!line) return null;
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
if (n == -1) return null;
|
|
1638
|
+
} else {
|
|
1639
|
+
var n = lineNo(line);
|
|
1640
|
+
if (n == null) return null;
|
|
1109
1641
|
}
|
|
1110
1642
|
var marker = line.gutterMarker;
|
|
1111
|
-
return {line: n, text: line.text, markerText: marker && marker.text,
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1643
|
+
return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
|
|
1644
|
+
markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
function measureLine(line, ch) {
|
|
1648
|
+
if (ch == 0) return {top: 0, left: 0};
|
|
1649
|
+
var wbr = options.lineWrapping && ch < line.text.length &&
|
|
1650
|
+
spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
|
|
1651
|
+
var pre = lineContent(line, ch);
|
|
1652
|
+
removeChildrenAndAdd(measure, pre);
|
|
1653
|
+
var anchor = pre.anchor;
|
|
1654
|
+
var top = anchor.offsetTop, left = anchor.offsetLeft;
|
|
1655
|
+
// Older IEs report zero offsets for spans directly after a wrap
|
|
1656
|
+
if (ie && top == 0 && left == 0) {
|
|
1657
|
+
var backup = elt("span", "x");
|
|
1658
|
+
anchor.parentNode.insertBefore(backup, anchor.nextSibling);
|
|
1659
|
+
top = backup.offsetTop;
|
|
1660
|
+
}
|
|
1661
|
+
return {top: top, left: left};
|
|
1125
1662
|
}
|
|
1126
|
-
function
|
|
1127
|
-
|
|
1128
|
-
|
|
1663
|
+
function localCoords(pos, inLineWrap) {
|
|
1664
|
+
var x, lh = textHeight(), y = lh * (heightAtLine(doc, pos.line) - (inLineWrap ? displayOffset : 0));
|
|
1665
|
+
if (pos.ch == 0) x = 0;
|
|
1666
|
+
else {
|
|
1667
|
+
var sp = measureLine(getLine(pos.line), pos.ch);
|
|
1668
|
+
x = sp.left;
|
|
1669
|
+
if (options.lineWrapping) y += Math.max(0, sp.top);
|
|
1670
|
+
}
|
|
1671
|
+
return {x: x, y: y, yBot: y + lh};
|
|
1672
|
+
}
|
|
1673
|
+
// Coords must be lineSpace-local
|
|
1674
|
+
function coordsChar(x, y) {
|
|
1675
|
+
var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th);
|
|
1676
|
+
if (heightPos < 0) return {line: 0, ch: 0};
|
|
1677
|
+
var lineNo = lineAtHeight(doc, heightPos);
|
|
1678
|
+
if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length};
|
|
1679
|
+
var lineObj = getLine(lineNo), text = lineObj.text;
|
|
1680
|
+
var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;
|
|
1681
|
+
if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0};
|
|
1682
|
+
var wrongLine = false;
|
|
1129
1683
|
function getX(len) {
|
|
1130
|
-
|
|
1131
|
-
|
|
1684
|
+
var sp = measureLine(lineObj, len);
|
|
1685
|
+
if (tw) {
|
|
1686
|
+
var off = Math.round(sp.top / th);
|
|
1687
|
+
wrongLine = off != innerOff;
|
|
1688
|
+
return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth);
|
|
1689
|
+
}
|
|
1690
|
+
return sp.left;
|
|
1132
1691
|
}
|
|
1133
1692
|
var from = 0, fromX = 0, to = text.length, toX;
|
|
1134
1693
|
// Guess a suitable upper bound for our search.
|
|
1135
|
-
var estimated = Math.min(to, Math.ceil(x /
|
|
1694
|
+
var estimated = Math.min(to, Math.ceil((x + innerOff * scroller.clientWidth * .9) / cw));
|
|
1136
1695
|
for (;;) {
|
|
1137
1696
|
var estX = getX(estimated);
|
|
1138
1697
|
if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
|
|
1139
1698
|
else {toX = estX; to = estimated; break;}
|
|
1140
1699
|
}
|
|
1141
|
-
if (x > toX) return to;
|
|
1700
|
+
if (x > toX) return {line: lineNo, ch: to};
|
|
1142
1701
|
// Try to guess a suitable lower bound as well.
|
|
1143
1702
|
estimated = Math.floor(to * 0.8); estX = getX(estimated);
|
|
1144
1703
|
if (estX < x) {from = estimated; fromX = estX;}
|
|
1145
1704
|
// Do a binary search between these bounds.
|
|
1146
1705
|
for (;;) {
|
|
1147
|
-
if (to - from <= 1)
|
|
1706
|
+
if (to - from <= 1) {
|
|
1707
|
+
var after = x - fromX < toX - x;
|
|
1708
|
+
return {line: lineNo, ch: after ? from : to, after: after};
|
|
1709
|
+
}
|
|
1148
1710
|
var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
|
|
1149
|
-
if (middleX > x) {to = middle; toX = middleX;}
|
|
1711
|
+
if (middleX > x) {to = middle; toX = middleX; if (wrongLine) toX += 1000; }
|
|
1150
1712
|
else {from = middle; fromX = middleX;}
|
|
1151
1713
|
}
|
|
1152
1714
|
}
|
|
1153
|
-
|
|
1154
|
-
function localCoords(pos, inLineWrap) {
|
|
1155
|
-
var lh = lineHeight(), line = pos.line - (inLineWrap ? showingFrom : 0);
|
|
1156
|
-
return {x: charX(pos.line, pos.ch), y: line * lh, yBot: (line + 1) * lh};
|
|
1157
|
-
}
|
|
1158
1715
|
function pageCoords(pos) {
|
|
1159
1716
|
var local = localCoords(pos, true), off = eltOffset(lineSpace);
|
|
1160
1717
|
return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
|
|
1161
1718
|
}
|
|
1162
1719
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
if (
|
|
1166
|
-
|
|
1167
|
-
|
|
1720
|
+
var cachedHeight, cachedHeightFor, measurePre;
|
|
1721
|
+
function textHeight() {
|
|
1722
|
+
if (measurePre == null) {
|
|
1723
|
+
measurePre = elt("pre");
|
|
1724
|
+
for (var i = 0; i < 49; ++i) {
|
|
1725
|
+
measurePre.appendChild(document.createTextNode("x"));
|
|
1726
|
+
measurePre.appendChild(elt("br"));
|
|
1727
|
+
}
|
|
1728
|
+
measurePre.appendChild(document.createTextNode("x"));
|
|
1729
|
+
}
|
|
1730
|
+
var offsetHeight = lineDiv.clientHeight;
|
|
1731
|
+
if (offsetHeight == cachedHeightFor) return cachedHeight;
|
|
1732
|
+
cachedHeightFor = offsetHeight;
|
|
1733
|
+
removeChildrenAndAdd(measure, measurePre.cloneNode(true));
|
|
1734
|
+
cachedHeight = measure.firstChild.offsetHeight / 50 || 1;
|
|
1735
|
+
removeChildren(measure);
|
|
1736
|
+
return cachedHeight;
|
|
1737
|
+
}
|
|
1738
|
+
var cachedWidth, cachedWidthFor = 0;
|
|
1739
|
+
function charWidth() {
|
|
1740
|
+
if (scroller.clientWidth == cachedWidthFor) return cachedWidth;
|
|
1741
|
+
cachedWidthFor = scroller.clientWidth;
|
|
1742
|
+
var anchor = elt("span", "x");
|
|
1743
|
+
var pre = elt("pre", [anchor]);
|
|
1744
|
+
removeChildrenAndAdd(measure, pre);
|
|
1745
|
+
return (cachedWidth = anchor.offsetWidth || 10);
|
|
1168
1746
|
}
|
|
1169
1747
|
function paddingTop() {return lineSpace.offsetTop;}
|
|
1170
1748
|
function paddingLeft() {return lineSpace.offsetLeft;}
|
|
@@ -1179,42 +1757,53 @@ var CodeMirror = (function() {
|
|
|
1179
1757
|
if (!liberal && (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight))
|
|
1180
1758
|
return null;
|
|
1181
1759
|
var offL = eltOffset(lineSpace, true);
|
|
1182
|
-
|
|
1183
|
-
return clipPos({line: line, ch: charFromX(clipLine(line), x - offL.left)});
|
|
1760
|
+
return coordsChar(x - offL.left, y - offL.top);
|
|
1184
1761
|
}
|
|
1762
|
+
var detectingSelectAll;
|
|
1185
1763
|
function onContextMenu(e) {
|
|
1186
|
-
var pos = posFromMouse(e);
|
|
1187
|
-
if (!pos ||
|
|
1764
|
+
var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
|
|
1765
|
+
if (!pos || opera) return; // Opera is difficult.
|
|
1188
1766
|
if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
|
|
1189
1767
|
operation(setCursor)(pos.line, pos.ch);
|
|
1190
1768
|
|
|
1191
1769
|
var oldCSS = input.style.cssText;
|
|
1192
1770
|
inputDiv.style.position = "absolute";
|
|
1193
|
-
input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (
|
|
1194
|
-
"px; left: " + (
|
|
1771
|
+
input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
|
|
1772
|
+
"px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
|
|
1195
1773
|
"border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
|
|
1196
|
-
leaveInputAlone = true;
|
|
1197
|
-
var val = input.value = getSelection();
|
|
1198
1774
|
focusInput();
|
|
1199
|
-
|
|
1775
|
+
resetInput(true);
|
|
1776
|
+
// Adds "Select all" to context menu in FF
|
|
1777
|
+
if (posEq(sel.from, sel.to)) input.value = prevInput = " ";
|
|
1778
|
+
|
|
1200
1779
|
function rehide() {
|
|
1201
|
-
var newVal = splitLines(input.value).join("\n");
|
|
1202
|
-
if (newVal != val) operation(replaceSelection)(newVal, "end");
|
|
1203
1780
|
inputDiv.style.position = "relative";
|
|
1204
1781
|
input.style.cssText = oldCSS;
|
|
1205
|
-
|
|
1206
|
-
prepareInput();
|
|
1782
|
+
if (ie_lt9) scrollbar.scrollTop = scrollPos;
|
|
1207
1783
|
slowPoll();
|
|
1784
|
+
|
|
1785
|
+
// Try to detect the user choosing select-all
|
|
1786
|
+
if (input.selectionStart != null) {
|
|
1787
|
+
clearTimeout(detectingSelectAll);
|
|
1788
|
+
var extval = input.value = " " + (posEq(sel.from, sel.to) ? "" : input.value), i = 0;
|
|
1789
|
+
prevInput = " ";
|
|
1790
|
+
input.selectionStart = 1; input.selectionEnd = extval.length;
|
|
1791
|
+
detectingSelectAll = setTimeout(function poll(){
|
|
1792
|
+
if (prevInput == " " && input.selectionStart == 0)
|
|
1793
|
+
operation(commands.selectAll)(instance);
|
|
1794
|
+
else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
|
|
1795
|
+
else resetInput();
|
|
1796
|
+
}, 200);
|
|
1797
|
+
}
|
|
1208
1798
|
}
|
|
1209
|
-
|
|
1799
|
+
|
|
1210
1800
|
if (gecko) {
|
|
1211
1801
|
e_stop(e);
|
|
1212
1802
|
var mouseup = connect(window, "mouseup", function() {
|
|
1213
1803
|
mouseup();
|
|
1214
1804
|
setTimeout(rehide, 20);
|
|
1215
1805
|
}, true);
|
|
1216
|
-
}
|
|
1217
|
-
else {
|
|
1806
|
+
} else {
|
|
1218
1807
|
setTimeout(rehide, 50);
|
|
1219
1808
|
}
|
|
1220
1809
|
}
|
|
@@ -1226,12 +1815,12 @@ var CodeMirror = (function() {
|
|
|
1226
1815
|
cursor.style.visibility = "";
|
|
1227
1816
|
blinker = setInterval(function() {
|
|
1228
1817
|
cursor.style.visibility = (on = !on) ? "" : "hidden";
|
|
1229
|
-
},
|
|
1818
|
+
}, options.cursorBlinkRate);
|
|
1230
1819
|
}
|
|
1231
1820
|
|
|
1232
1821
|
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
|
1233
1822
|
function matchBrackets(autoclear) {
|
|
1234
|
-
var head = sel.inverted ? sel.from : sel.to, line =
|
|
1823
|
+
var head = sel.inverted ? sel.from : sel.to, line = getLine(head.line), pos = head.ch - 1;
|
|
1235
1824
|
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
|
|
1236
1825
|
if (!match) return;
|
|
1237
1826
|
var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles;
|
|
@@ -1244,7 +1833,7 @@ var CodeMirror = (function() {
|
|
|
1244
1833
|
var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
|
|
1245
1834
|
for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
|
|
1246
1835
|
var text = st[i];
|
|
1247
|
-
if (st[i+1] !=
|
|
1836
|
+
if (st[i+1] != style) {pos += d * text.length; continue;}
|
|
1248
1837
|
for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
|
|
1249
1838
|
if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
|
|
1250
1839
|
var match = matching[cur];
|
|
@@ -1255,18 +1844,16 @@ var CodeMirror = (function() {
|
|
|
1255
1844
|
}
|
|
1256
1845
|
}
|
|
1257
1846
|
}
|
|
1258
|
-
for (var i = head.line, e = forward ? Math.min(i + 100,
|
|
1259
|
-
var line =
|
|
1847
|
+
for (var i = head.line, e = forward ? Math.min(i + 100, doc.size) : Math.max(-1, i - 100); i != e; i+=d) {
|
|
1848
|
+
var line = getLine(i), first = i == head.line;
|
|
1260
1849
|
var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length);
|
|
1261
1850
|
if (found) break;
|
|
1262
1851
|
}
|
|
1263
1852
|
if (!found) found = {pos: null, match: false};
|
|
1264
1853
|
var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
|
|
1265
1854
|
var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style),
|
|
1266
|
-
two = found.pos != null
|
|
1267
|
-
|
|
1268
|
-
: function() {};
|
|
1269
|
-
var clear = operation(function(){one(); two();});
|
|
1855
|
+
two = found.pos != null && markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style);
|
|
1856
|
+
var clear = operation(function(){one.clear(); two && two.clear();});
|
|
1270
1857
|
if (autoclear) setTimeout(clear, 800);
|
|
1271
1858
|
else bracketHighlighted = clear;
|
|
1272
1859
|
}
|
|
@@ -1280,73 +1867,50 @@ var CodeMirror = (function() {
|
|
|
1280
1867
|
var minindent, minline;
|
|
1281
1868
|
for (var search = n, lim = n - 40; search > lim; --search) {
|
|
1282
1869
|
if (search == 0) return 0;
|
|
1283
|
-
var line =
|
|
1870
|
+
var line = getLine(search-1);
|
|
1284
1871
|
if (line.stateAfter) return search;
|
|
1285
|
-
var indented = line.indentation();
|
|
1872
|
+
var indented = line.indentation(options.tabSize);
|
|
1286
1873
|
if (minline == null || minindent > indented) {
|
|
1287
|
-
minline = search;
|
|
1874
|
+
minline = search - 1;
|
|
1288
1875
|
minindent = indented;
|
|
1289
1876
|
}
|
|
1290
1877
|
}
|
|
1291
1878
|
return minline;
|
|
1292
1879
|
}
|
|
1293
1880
|
function getStateBefore(n) {
|
|
1294
|
-
var
|
|
1881
|
+
var pos = findStartLine(n), state = pos && getLine(pos-1).stateAfter;
|
|
1295
1882
|
if (!state) state = startState(mode);
|
|
1296
1883
|
else state = copyState(mode, state);
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
line.
|
|
1300
|
-
|
|
1301
|
-
}
|
|
1302
|
-
if (n < lines.length && !lines[n].stateAfter) work.push(n);
|
|
1884
|
+
doc.iter(pos, n, function(line) {
|
|
1885
|
+
line.process(mode, state, options.tabSize);
|
|
1886
|
+
line.stateAfter = (pos == n - 1 || pos % 5 == 0) ? copyState(mode, state) : null;
|
|
1887
|
+
});
|
|
1303
1888
|
return state;
|
|
1304
1889
|
}
|
|
1305
|
-
function highlightLines(start, end) {
|
|
1306
|
-
var state = getStateBefore(start);
|
|
1307
|
-
for (var i = start; i < end; ++i) {
|
|
1308
|
-
var line = lines[i];
|
|
1309
|
-
line.highlight(mode, state);
|
|
1310
|
-
line.stateAfter = copyState(mode, state);
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
1890
|
function highlightWorker() {
|
|
1314
|
-
|
|
1315
|
-
var
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
var start = findStartLine(task), state = start && lines[start-1].stateAfter;
|
|
1321
|
-
if (state) state = copyState(mode, state);
|
|
1322
|
-
else state = startState(mode);
|
|
1323
|
-
|
|
1324
|
-
var unchanged = 0, compare = mode.compareStates;
|
|
1325
|
-
for (var i = start, l = lines.length; i < l; ++i) {
|
|
1326
|
-
var line = lines[i], hadState = line.stateAfter;
|
|
1327
|
-
if (+new Date > end) {
|
|
1328
|
-
work.push(i);
|
|
1329
|
-
startWorker(options.workDelay);
|
|
1330
|
-
changes.push({from: task, to: i + 1});
|
|
1331
|
-
return;
|
|
1332
|
-
}
|
|
1333
|
-
var changed = line.highlight(mode, state);
|
|
1891
|
+
if (frontier >= showingTo) return;
|
|
1892
|
+
var end = +new Date + options.workTime, state = copyState(mode, getStateBefore(frontier));
|
|
1893
|
+
var startFrontier = frontier;
|
|
1894
|
+
doc.iter(frontier, showingTo, function(line) {
|
|
1895
|
+
if (frontier >= showingFrom) { // Visible
|
|
1896
|
+
line.highlight(mode, state, options.tabSize);
|
|
1334
1897
|
line.stateAfter = copyState(mode, state);
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
if (changed || !hadState) unchanged = 0;
|
|
1339
|
-
else if (++unchanged > 3) break;
|
|
1340
|
-
}
|
|
1898
|
+
} else {
|
|
1899
|
+
line.process(mode, state, options.tabSize);
|
|
1900
|
+
line.stateAfter = frontier % 5 == 0 ? copyState(mode, state) : null;
|
|
1341
1901
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1902
|
+
++frontier;
|
|
1903
|
+
if (+new Date > end) {
|
|
1904
|
+
startWorker(options.workDelay);
|
|
1905
|
+
return true;
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
if (showingTo > startFrontier && frontier >= showingFrom)
|
|
1909
|
+
operation(function() {changes.push({from: startFrontier, to: frontier});})();
|
|
1346
1910
|
}
|
|
1347
1911
|
function startWorker(time) {
|
|
1348
|
-
if (
|
|
1349
|
-
|
|
1912
|
+
if (frontier < showingTo)
|
|
1913
|
+
highlight.set(time, highlightWorker);
|
|
1350
1914
|
}
|
|
1351
1915
|
|
|
1352
1916
|
// Operations are used to wrap changes in such a way that each
|
|
@@ -1354,32 +1918,48 @@ var CodeMirror = (function() {
|
|
|
1354
1918
|
// be awkward, slow, and error-prone), but instead updates are
|
|
1355
1919
|
// batched and then all combined and executed at once.
|
|
1356
1920
|
function startOperation() {
|
|
1357
|
-
updateInput =
|
|
1921
|
+
updateInput = userSelChange = textChanged = null;
|
|
1922
|
+
changes = []; selectionChanged = false; callbacks = [];
|
|
1358
1923
|
}
|
|
1359
1924
|
function endOperation() {
|
|
1360
|
-
|
|
1361
|
-
if (
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1925
|
+
if (updateMaxLine) computeMaxLength();
|
|
1926
|
+
if (maxLineChanged && !options.lineWrapping) {
|
|
1927
|
+
var cursorWidth = widthForcer.offsetWidth, left = measureLine(maxLine, maxLine.text.length).left;
|
|
1928
|
+
if (!ie_lt8) {
|
|
1929
|
+
widthForcer.style.left = left + "px";
|
|
1930
|
+
lineSpace.style.minWidth = (left + cursorWidth) + "px";
|
|
1931
|
+
}
|
|
1932
|
+
maxLineChanged = false;
|
|
1933
|
+
}
|
|
1934
|
+
var newScrollPos, updated;
|
|
1935
|
+
if (selectionChanged) {
|
|
1936
|
+
var coords = calculateCursorCoords();
|
|
1937
|
+
newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
|
|
1938
|
+
}
|
|
1939
|
+
if (changes.length || newScrollPos && newScrollPos.scrollTop != null)
|
|
1940
|
+
updated = updateDisplay(changes, true, newScrollPos && newScrollPos.scrollTop);
|
|
1941
|
+
if (!updated) {
|
|
1942
|
+
if (selectionChanged) updateSelection();
|
|
1943
|
+
if (gutterDirty) updateGutter();
|
|
1944
|
+
}
|
|
1945
|
+
if (newScrollPos) scrollCursorIntoView();
|
|
1365
1946
|
if (selectionChanged) restartBlink();
|
|
1366
1947
|
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
if (focused && !leaveInputAlone &&
|
|
1370
|
-
(updateInput === true || (updateInput !== false && selectionChanged)))
|
|
1371
|
-
prepareInput();
|
|
1948
|
+
if (focused && (updateInput === true || (updateInput !== false && selectionChanged)))
|
|
1949
|
+
resetInput(userSelChange);
|
|
1372
1950
|
|
|
1373
1951
|
if (selectionChanged && options.matchBrackets)
|
|
1374
1952
|
setTimeout(operation(function() {
|
|
1375
1953
|
if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
|
|
1376
|
-
matchBrackets(false);
|
|
1954
|
+
if (posEq(sel.from, sel.to)) matchBrackets(false);
|
|
1377
1955
|
}), 20);
|
|
1378
|
-
var
|
|
1379
|
-
if (
|
|
1956
|
+
var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
|
|
1957
|
+
if (textChanged && options.onChange && instance)
|
|
1958
|
+
options.onChange(instance, textChanged);
|
|
1959
|
+
if (sc && options.onCursorActivity)
|
|
1380
1960
|
options.onCursorActivity(instance);
|
|
1381
|
-
|
|
1382
|
-
|
|
1961
|
+
for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
|
|
1962
|
+
if (updated && options.onUpdate) options.onUpdate(instance);
|
|
1383
1963
|
}
|
|
1384
1964
|
var nestedOperation = 0;
|
|
1385
1965
|
function operation(f) {
|
|
@@ -1391,120 +1971,11 @@ var CodeMirror = (function() {
|
|
|
1391
1971
|
};
|
|
1392
1972
|
}
|
|
1393
1973
|
|
|
1394
|
-
function
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
if (pos && typeof pos == "object") pos = clipPos(pos);
|
|
1399
|
-
else pos = {line: 0, ch: 0};
|
|
1400
|
-
this.pos = {from: pos, to: pos};
|
|
1401
|
-
|
|
1402
|
-
// The matches method is filled in based on the type of query.
|
|
1403
|
-
// It takes a position and a direction, and returns an object
|
|
1404
|
-
// describing the next occurrence of the query, or null if no
|
|
1405
|
-
// more matches were found.
|
|
1406
|
-
if (typeof query != "string") // Regexp match
|
|
1407
|
-
this.matches = function(reverse, pos) {
|
|
1408
|
-
if (reverse) {
|
|
1409
|
-
var line = lines[pos.line].text.slice(0, pos.ch), match = line.match(query), start = 0;
|
|
1410
|
-
while (match) {
|
|
1411
|
-
var ind = line.indexOf(match[0]);
|
|
1412
|
-
start += ind;
|
|
1413
|
-
line = line.slice(ind + 1);
|
|
1414
|
-
var newmatch = line.match(query);
|
|
1415
|
-
if (newmatch) match = newmatch;
|
|
1416
|
-
else break;
|
|
1417
|
-
start++;
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
else {
|
|
1421
|
-
var line = lines[pos.line].text.slice(pos.ch), match = line.match(query),
|
|
1422
|
-
start = match && pos.ch + line.indexOf(match[0]);
|
|
1423
|
-
}
|
|
1424
|
-
if (match)
|
|
1425
|
-
return {from: {line: pos.line, ch: start},
|
|
1426
|
-
to: {line: pos.line, ch: start + match[0].length},
|
|
1427
|
-
match: match};
|
|
1428
|
-
};
|
|
1429
|
-
else { // String query
|
|
1430
|
-
if (caseFold) query = query.toLowerCase();
|
|
1431
|
-
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
|
|
1432
|
-
var target = query.split("\n");
|
|
1433
|
-
// Different methods for single-line and multi-line queries
|
|
1434
|
-
if (target.length == 1)
|
|
1435
|
-
this.matches = function(reverse, pos) {
|
|
1436
|
-
var line = fold(lines[pos.line].text), len = query.length, match;
|
|
1437
|
-
if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
|
|
1438
|
-
: (match = line.indexOf(query, pos.ch)) != -1)
|
|
1439
|
-
return {from: {line: pos.line, ch: match},
|
|
1440
|
-
to: {line: pos.line, ch: match + len}};
|
|
1441
|
-
};
|
|
1442
|
-
else
|
|
1443
|
-
this.matches = function(reverse, pos) {
|
|
1444
|
-
var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(lines[ln].text);
|
|
1445
|
-
var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
|
|
1446
|
-
if (reverse ? offsetA >= pos.ch || offsetA != match.length
|
|
1447
|
-
: offsetA <= pos.ch || offsetA != line.length - match.length)
|
|
1448
|
-
return;
|
|
1449
|
-
for (;;) {
|
|
1450
|
-
if (reverse ? !ln : ln == lines.length - 1) return;
|
|
1451
|
-
line = fold(lines[ln += reverse ? -1 : 1].text);
|
|
1452
|
-
match = target[reverse ? --idx : ++idx];
|
|
1453
|
-
if (idx > 0 && idx < target.length - 1) {
|
|
1454
|
-
if (line != match) return;
|
|
1455
|
-
else continue;
|
|
1456
|
-
}
|
|
1457
|
-
var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
|
|
1458
|
-
if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
|
|
1459
|
-
return;
|
|
1460
|
-
var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
|
|
1461
|
-
return {from: reverse ? end : start, to: reverse ? start : end};
|
|
1462
|
-
}
|
|
1463
|
-
};
|
|
1464
|
-
}
|
|
1974
|
+
function compoundChange(f) {
|
|
1975
|
+
history.startCompound();
|
|
1976
|
+
try { return f(); } finally { history.endCompound(); }
|
|
1465
1977
|
}
|
|
1466
1978
|
|
|
1467
|
-
SearchCursor.prototype = {
|
|
1468
|
-
findNext: function() {return this.find(false);},
|
|
1469
|
-
findPrevious: function() {return this.find(true);},
|
|
1470
|
-
|
|
1471
|
-
find: function(reverse) {
|
|
1472
|
-
var self = this, pos = clipPos(reverse ? this.pos.from : this.pos.to);
|
|
1473
|
-
function savePosAndFail(line) {
|
|
1474
|
-
var pos = {line: line, ch: 0};
|
|
1475
|
-
self.pos = {from: pos, to: pos};
|
|
1476
|
-
self.atOccurrence = false;
|
|
1477
|
-
return false;
|
|
1478
|
-
}
|
|
1479
|
-
|
|
1480
|
-
for (;;) {
|
|
1481
|
-
if (this.pos = this.matches(reverse, pos)) {
|
|
1482
|
-
this.atOccurrence = true;
|
|
1483
|
-
return this.pos.match || true;
|
|
1484
|
-
}
|
|
1485
|
-
if (reverse) {
|
|
1486
|
-
if (!pos.line) return savePosAndFail(0);
|
|
1487
|
-
pos = {line: pos.line-1, ch: lines[pos.line-1].text.length};
|
|
1488
|
-
}
|
|
1489
|
-
else {
|
|
1490
|
-
if (pos.line == lines.length - 1) return savePosAndFail(lines.length);
|
|
1491
|
-
pos = {line: pos.line+1, ch: 0};
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
},
|
|
1495
|
-
|
|
1496
|
-
from: function() {if (this.atOccurrence) return copyPos(this.pos.from);},
|
|
1497
|
-
to: function() {if (this.atOccurrence) return copyPos(this.pos.to);},
|
|
1498
|
-
|
|
1499
|
-
replace: function(newText) {
|
|
1500
|
-
var self = this;
|
|
1501
|
-
if (this.atOccurrence)
|
|
1502
|
-
operation(function() {
|
|
1503
|
-
self.pos.to = replaceRange(newText, self.pos.from, self.pos.to);
|
|
1504
|
-
})();
|
|
1505
|
-
}
|
|
1506
|
-
};
|
|
1507
|
-
|
|
1508
1979
|
for (var ext in extensions)
|
|
1509
1980
|
if (extensions.propertyIsEnumerable(ext) &&
|
|
1510
1981
|
!instance.propertyIsEnumerable(ext))
|
|
@@ -1519,49 +1990,74 @@ var CodeMirror = (function() {
|
|
|
1519
1990
|
theme: "default",
|
|
1520
1991
|
indentUnit: 2,
|
|
1521
1992
|
indentWithTabs: false,
|
|
1522
|
-
|
|
1523
|
-
|
|
1993
|
+
smartIndent: true,
|
|
1994
|
+
tabSize: 4,
|
|
1995
|
+
keyMap: "default",
|
|
1996
|
+
extraKeys: null,
|
|
1524
1997
|
electricChars: true,
|
|
1998
|
+
autoClearEmptyLines: false,
|
|
1525
1999
|
onKeyEvent: null,
|
|
2000
|
+
onDragEvent: null,
|
|
2001
|
+
lineWrapping: false,
|
|
1526
2002
|
lineNumbers: false,
|
|
1527
2003
|
gutter: false,
|
|
2004
|
+
fixedGutter: false,
|
|
1528
2005
|
firstLineNumber: 1,
|
|
1529
2006
|
readOnly: false,
|
|
2007
|
+
dragDrop: true,
|
|
1530
2008
|
onChange: null,
|
|
1531
2009
|
onCursorActivity: null,
|
|
2010
|
+
onViewportChange: null,
|
|
1532
2011
|
onGutterClick: null,
|
|
1533
|
-
|
|
2012
|
+
onUpdate: null,
|
|
1534
2013
|
onFocus: null, onBlur: null, onScroll: null,
|
|
1535
2014
|
matchBrackets: false,
|
|
2015
|
+
cursorBlinkRate: 530,
|
|
1536
2016
|
workTime: 100,
|
|
1537
2017
|
workDelay: 200,
|
|
2018
|
+
pollInterval: 100,
|
|
1538
2019
|
undoDepth: 40,
|
|
1539
2020
|
tabindex: null,
|
|
1540
|
-
|
|
2021
|
+
autofocus: null,
|
|
2022
|
+
lineNumberFormatter: function(integer) { return integer; }
|
|
1541
2023
|
};
|
|
1542
2024
|
|
|
2025
|
+
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
|
|
2026
|
+
var mac = ios || /Mac/.test(navigator.platform);
|
|
2027
|
+
var win = /Win/.test(navigator.platform);
|
|
2028
|
+
|
|
1543
2029
|
// Known modes, by name and by MIME
|
|
1544
|
-
var modes = {}, mimeModes = {};
|
|
2030
|
+
var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
|
|
1545
2031
|
CodeMirror.defineMode = function(name, mode) {
|
|
1546
2032
|
if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
|
|
2033
|
+
if (arguments.length > 2) {
|
|
2034
|
+
mode.dependencies = [];
|
|
2035
|
+
for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
|
|
2036
|
+
}
|
|
1547
2037
|
modes[name] = mode;
|
|
1548
2038
|
};
|
|
1549
2039
|
CodeMirror.defineMIME = function(mime, spec) {
|
|
1550
2040
|
mimeModes[mime] = spec;
|
|
1551
2041
|
};
|
|
1552
|
-
CodeMirror.
|
|
2042
|
+
CodeMirror.resolveMode = function(spec) {
|
|
1553
2043
|
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
|
|
1554
2044
|
spec = mimeModes[spec];
|
|
1555
|
-
if (typeof spec == "string")
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
2045
|
+
else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
|
|
2046
|
+
return CodeMirror.resolveMode("application/xml");
|
|
2047
|
+
if (typeof spec == "string") return {name: spec};
|
|
2048
|
+
else return spec || {name: "null"};
|
|
2049
|
+
};
|
|
2050
|
+
CodeMirror.getMode = function(options, spec) {
|
|
2051
|
+
var spec = CodeMirror.resolveMode(spec);
|
|
2052
|
+
var mfactory = modes[spec.name];
|
|
2053
|
+
if (!mfactory) return CodeMirror.getMode(options, "text/plain");
|
|
2054
|
+
var modeObj = mfactory(options, spec);
|
|
2055
|
+
if (modeExtensions.hasOwnProperty(spec.name)) {
|
|
2056
|
+
var exts = modeExtensions[spec.name];
|
|
2057
|
+
for (var prop in exts) if (exts.hasOwnProperty(prop)) modeObj[prop] = exts[prop];
|
|
2058
|
+
}
|
|
2059
|
+
modeObj.name = spec.name;
|
|
2060
|
+
return modeObj;
|
|
1565
2061
|
};
|
|
1566
2062
|
CodeMirror.listModes = function() {
|
|
1567
2063
|
var list = [];
|
|
@@ -1572,20 +2068,159 @@ var CodeMirror = (function() {
|
|
|
1572
2068
|
CodeMirror.listMIMEs = function() {
|
|
1573
2069
|
var list = [];
|
|
1574
2070
|
for (var m in mimeModes)
|
|
1575
|
-
if (mimeModes.propertyIsEnumerable(m)) list.push(m);
|
|
2071
|
+
if (mimeModes.propertyIsEnumerable(m)) list.push({mime: m, mode: mimeModes[m]});
|
|
1576
2072
|
return list;
|
|
1577
2073
|
};
|
|
1578
2074
|
|
|
1579
|
-
var extensions = {};
|
|
2075
|
+
var extensions = CodeMirror.extensions = {};
|
|
1580
2076
|
CodeMirror.defineExtension = function(name, func) {
|
|
1581
2077
|
extensions[name] = func;
|
|
1582
2078
|
};
|
|
1583
2079
|
|
|
2080
|
+
var modeExtensions = CodeMirror.modeExtensions = {};
|
|
2081
|
+
CodeMirror.extendMode = function(mode, properties) {
|
|
2082
|
+
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
|
|
2083
|
+
for (var prop in properties) if (properties.hasOwnProperty(prop))
|
|
2084
|
+
exts[prop] = properties[prop];
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
var commands = CodeMirror.commands = {
|
|
2088
|
+
selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
|
|
2089
|
+
killLine: function(cm) {
|
|
2090
|
+
var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
|
|
2091
|
+
if (!sel && cm.getLine(from.line).length == from.ch) cm.replaceRange("", from, {line: from.line + 1, ch: 0});
|
|
2092
|
+
else cm.replaceRange("", from, sel ? to : {line: from.line});
|
|
2093
|
+
},
|
|
2094
|
+
deleteLine: function(cm) {var l = cm.getCursor().line; cm.replaceRange("", {line: l, ch: 0}, {line: l});},
|
|
2095
|
+
undo: function(cm) {cm.undo();},
|
|
2096
|
+
redo: function(cm) {cm.redo();},
|
|
2097
|
+
goDocStart: function(cm) {cm.setCursor(0, 0, true);},
|
|
2098
|
+
goDocEnd: function(cm) {cm.setSelection({line: cm.lineCount() - 1}, null, true);},
|
|
2099
|
+
goLineStart: function(cm) {cm.setCursor(cm.getCursor().line, 0, true);},
|
|
2100
|
+
goLineStartSmart: function(cm) {
|
|
2101
|
+
var cur = cm.getCursor();
|
|
2102
|
+
var text = cm.getLine(cur.line), firstNonWS = Math.max(0, text.search(/\S/));
|
|
2103
|
+
cm.setCursor(cur.line, cur.ch <= firstNonWS && cur.ch ? 0 : firstNonWS, true);
|
|
2104
|
+
},
|
|
2105
|
+
goLineEnd: function(cm) {cm.setSelection({line: cm.getCursor().line}, null, true);},
|
|
2106
|
+
goLineUp: function(cm) {cm.moveV(-1, "line");},
|
|
2107
|
+
goLineDown: function(cm) {cm.moveV(1, "line");},
|
|
2108
|
+
goPageUp: function(cm) {cm.moveV(-1, "page");},
|
|
2109
|
+
goPageDown: function(cm) {cm.moveV(1, "page");},
|
|
2110
|
+
goCharLeft: function(cm) {cm.moveH(-1, "char");},
|
|
2111
|
+
goCharRight: function(cm) {cm.moveH(1, "char");},
|
|
2112
|
+
goColumnLeft: function(cm) {cm.moveH(-1, "column");},
|
|
2113
|
+
goColumnRight: function(cm) {cm.moveH(1, "column");},
|
|
2114
|
+
goWordLeft: function(cm) {cm.moveH(-1, "word");},
|
|
2115
|
+
goWordRight: function(cm) {cm.moveH(1, "word");},
|
|
2116
|
+
delCharLeft: function(cm) {cm.deleteH(-1, "char");},
|
|
2117
|
+
delCharRight: function(cm) {cm.deleteH(1, "char");},
|
|
2118
|
+
delWordLeft: function(cm) {cm.deleteH(-1, "word");},
|
|
2119
|
+
delWordRight: function(cm) {cm.deleteH(1, "word");},
|
|
2120
|
+
indentAuto: function(cm) {cm.indentSelection("smart");},
|
|
2121
|
+
indentMore: function(cm) {cm.indentSelection("add");},
|
|
2122
|
+
indentLess: function(cm) {cm.indentSelection("subtract");},
|
|
2123
|
+
insertTab: function(cm) {cm.replaceSelection("\t", "end");},
|
|
2124
|
+
defaultTab: function(cm) {
|
|
2125
|
+
if (cm.somethingSelected()) cm.indentSelection("add");
|
|
2126
|
+
else cm.replaceSelection("\t", "end");
|
|
2127
|
+
},
|
|
2128
|
+
transposeChars: function(cm) {
|
|
2129
|
+
var cur = cm.getCursor(), line = cm.getLine(cur.line);
|
|
2130
|
+
if (cur.ch > 0 && cur.ch < line.length - 1)
|
|
2131
|
+
cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
|
|
2132
|
+
{line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1});
|
|
2133
|
+
},
|
|
2134
|
+
newlineAndIndent: function(cm) {
|
|
2135
|
+
cm.replaceSelection("\n", "end");
|
|
2136
|
+
cm.indentLine(cm.getCursor().line);
|
|
2137
|
+
},
|
|
2138
|
+
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
|
|
2139
|
+
};
|
|
2140
|
+
|
|
2141
|
+
var keyMap = CodeMirror.keyMap = {};
|
|
2142
|
+
keyMap.basic = {
|
|
2143
|
+
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
|
|
2144
|
+
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
|
|
2145
|
+
"Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
|
|
2146
|
+
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
|
|
2147
|
+
};
|
|
2148
|
+
// Note that the save and find-related commands aren't defined by
|
|
2149
|
+
// default. Unknown commands are simply ignored.
|
|
2150
|
+
keyMap.pcDefault = {
|
|
2151
|
+
"Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
|
|
2152
|
+
"Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
|
|
2153
|
+
"Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
|
|
2154
|
+
"Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
|
|
2155
|
+
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
|
|
2156
|
+
"Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
|
|
2157
|
+
fallthrough: "basic"
|
|
2158
|
+
};
|
|
2159
|
+
keyMap.macDefault = {
|
|
2160
|
+
"Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
|
|
2161
|
+
"Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft",
|
|
2162
|
+
"Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
|
|
2163
|
+
"Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
|
|
2164
|
+
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
|
|
2165
|
+
"Cmd-[": "indentLess", "Cmd-]": "indentMore",
|
|
2166
|
+
fallthrough: ["basic", "emacsy"]
|
|
2167
|
+
};
|
|
2168
|
+
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
|
|
2169
|
+
keyMap.emacsy = {
|
|
2170
|
+
"Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
|
|
2171
|
+
"Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
|
|
2172
|
+
"Ctrl-V": "goPageUp", "Shift-Ctrl-V": "goPageDown", "Ctrl-D": "delCharRight", "Ctrl-H": "delCharLeft",
|
|
2173
|
+
"Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
|
|
2174
|
+
};
|
|
2175
|
+
|
|
2176
|
+
function getKeyMap(val) {
|
|
2177
|
+
if (typeof val == "string") return keyMap[val];
|
|
2178
|
+
else return val;
|
|
2179
|
+
}
|
|
2180
|
+
function lookupKey(name, extraMap, map, handle, stop) {
|
|
2181
|
+
function lookup(map) {
|
|
2182
|
+
map = getKeyMap(map);
|
|
2183
|
+
var found = map[name];
|
|
2184
|
+
if (found === false) {
|
|
2185
|
+
if (stop) stop();
|
|
2186
|
+
return true;
|
|
2187
|
+
}
|
|
2188
|
+
if (found != null && handle(found)) return true;
|
|
2189
|
+
if (map.nofallthrough) {
|
|
2190
|
+
if (stop) stop();
|
|
2191
|
+
return true;
|
|
2192
|
+
}
|
|
2193
|
+
var fallthrough = map.fallthrough;
|
|
2194
|
+
if (fallthrough == null) return false;
|
|
2195
|
+
if (Object.prototype.toString.call(fallthrough) != "[object Array]")
|
|
2196
|
+
return lookup(fallthrough);
|
|
2197
|
+
for (var i = 0, e = fallthrough.length; i < e; ++i) {
|
|
2198
|
+
if (lookup(fallthrough[i])) return true;
|
|
2199
|
+
}
|
|
2200
|
+
return false;
|
|
2201
|
+
}
|
|
2202
|
+
if (extraMap && lookup(extraMap)) return true;
|
|
2203
|
+
return lookup(map);
|
|
2204
|
+
}
|
|
2205
|
+
function isModifierKey(event) {
|
|
2206
|
+
var name = keyNames[e_prop(event, "keyCode")];
|
|
2207
|
+
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
|
|
2208
|
+
}
|
|
2209
|
+
|
|
1584
2210
|
CodeMirror.fromTextArea = function(textarea, options) {
|
|
1585
2211
|
if (!options) options = {};
|
|
1586
2212
|
options.value = textarea.value;
|
|
1587
2213
|
if (!options.tabindex && textarea.tabindex)
|
|
1588
2214
|
options.tabindex = textarea.tabindex;
|
|
2215
|
+
// Set autofocus to true if this textarea is focused, or if it has
|
|
2216
|
+
// autofocus and no other element is focused.
|
|
2217
|
+
if (options.autofocus == null) {
|
|
2218
|
+
var hasFocus = document.body;
|
|
2219
|
+
// doc.activeElement occasionally throws on IE
|
|
2220
|
+
try { hasFocus = document.activeElement; } catch(e) {}
|
|
2221
|
+
options.autofocus = hasFocus == textarea ||
|
|
2222
|
+
textarea.getAttribute("autofocus") != null && hasFocus == document.body;
|
|
2223
|
+
}
|
|
1589
2224
|
|
|
1590
2225
|
function save() {textarea.value = instance.getValue();}
|
|
1591
2226
|
if (textarea.form) {
|
|
@@ -1593,13 +2228,12 @@ var CodeMirror = (function() {
|
|
|
1593
2228
|
var rmSubmit = connect(textarea.form, "submit", save, true);
|
|
1594
2229
|
if (typeof textarea.form.submit == "function") {
|
|
1595
2230
|
var realSubmit = textarea.form.submit;
|
|
1596
|
-
function wrappedSubmit() {
|
|
2231
|
+
textarea.form.submit = function wrappedSubmit() {
|
|
1597
2232
|
save();
|
|
1598
2233
|
textarea.form.submit = realSubmit;
|
|
1599
2234
|
textarea.form.submit();
|
|
1600
2235
|
textarea.form.submit = wrappedSubmit;
|
|
1601
|
-
}
|
|
1602
|
-
textarea.form.submit = wrappedSubmit;
|
|
2236
|
+
};
|
|
1603
2237
|
}
|
|
1604
2238
|
}
|
|
1605
2239
|
|
|
@@ -1608,6 +2242,7 @@ var CodeMirror = (function() {
|
|
|
1608
2242
|
textarea.parentNode.insertBefore(node, textarea.nextSibling);
|
|
1609
2243
|
}, options);
|
|
1610
2244
|
instance.save = save;
|
|
2245
|
+
instance.getTextArea = function() { return textarea; };
|
|
1611
2246
|
instance.toTextArea = function() {
|
|
1612
2247
|
save();
|
|
1613
2248
|
textarea.parentNode.removeChild(instance.getWrapperElement());
|
|
@@ -1621,6 +2256,18 @@ var CodeMirror = (function() {
|
|
|
1621
2256
|
return instance;
|
|
1622
2257
|
};
|
|
1623
2258
|
|
|
2259
|
+
var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
|
|
2260
|
+
var ie = /MSIE \d/.test(navigator.userAgent);
|
|
2261
|
+
var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
|
|
2262
|
+
var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
|
|
2263
|
+
var quirksMode = ie && document.documentMode == 5;
|
|
2264
|
+
var webkit = /WebKit\//.test(navigator.userAgent);
|
|
2265
|
+
var chrome = /Chrome\//.test(navigator.userAgent);
|
|
2266
|
+
var opera = /Opera\//.test(navigator.userAgent);
|
|
2267
|
+
var safari = /Apple Computer/.test(navigator.vendor);
|
|
2268
|
+
var khtml = /KHTML\//.test(navigator.userAgent);
|
|
2269
|
+
var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
|
|
2270
|
+
|
|
1624
2271
|
// Utility functions for working with state. Exported because modes
|
|
1625
2272
|
// sometimes need to do this.
|
|
1626
2273
|
function copyState(mode, state) {
|
|
@@ -1634,21 +2281,30 @@ var CodeMirror = (function() {
|
|
|
1634
2281
|
}
|
|
1635
2282
|
return nstate;
|
|
1636
2283
|
}
|
|
1637
|
-
CodeMirror.
|
|
2284
|
+
CodeMirror.copyState = copyState;
|
|
1638
2285
|
function startState(mode, a1, a2) {
|
|
1639
2286
|
return mode.startState ? mode.startState(a1, a2) : true;
|
|
1640
2287
|
}
|
|
1641
|
-
CodeMirror.
|
|
2288
|
+
CodeMirror.startState = startState;
|
|
2289
|
+
CodeMirror.innerMode = function(mode, state) {
|
|
2290
|
+
while (mode.innerMode) {
|
|
2291
|
+
var info = mode.innerMode(state);
|
|
2292
|
+
state = info.state;
|
|
2293
|
+
mode = info.mode;
|
|
2294
|
+
}
|
|
2295
|
+
return info || {mode: mode, state: state};
|
|
2296
|
+
};
|
|
1642
2297
|
|
|
1643
2298
|
// The character stream used by a mode's parser.
|
|
1644
|
-
function StringStream(string) {
|
|
2299
|
+
function StringStream(string, tabSize) {
|
|
1645
2300
|
this.pos = this.start = 0;
|
|
1646
2301
|
this.string = string;
|
|
2302
|
+
this.tabSize = tabSize || 8;
|
|
1647
2303
|
}
|
|
1648
2304
|
StringStream.prototype = {
|
|
1649
2305
|
eol: function() {return this.pos >= this.string.length;},
|
|
1650
2306
|
sol: function() {return this.pos == 0;},
|
|
1651
|
-
peek: function() {return this.string.charAt(this.pos);},
|
|
2307
|
+
peek: function() {return this.string.charAt(this.pos) || undefined;},
|
|
1652
2308
|
next: function() {
|
|
1653
2309
|
if (this.pos < this.string.length)
|
|
1654
2310
|
return this.string.charAt(this.pos++);
|
|
@@ -1660,7 +2316,7 @@ var CodeMirror = (function() {
|
|
|
1660
2316
|
if (ok) {++this.pos; return ch;}
|
|
1661
2317
|
},
|
|
1662
2318
|
eatWhile: function(match) {
|
|
1663
|
-
var start = this.
|
|
2319
|
+
var start = this.pos;
|
|
1664
2320
|
while (this.eat(match)){}
|
|
1665
2321
|
return this.pos > start;
|
|
1666
2322
|
},
|
|
@@ -1675,18 +2331,18 @@ var CodeMirror = (function() {
|
|
|
1675
2331
|
if (found > -1) {this.pos = found; return true;}
|
|
1676
2332
|
},
|
|
1677
2333
|
backUp: function(n) {this.pos -= n;},
|
|
1678
|
-
column: function() {return countColumn(this.string, this.start);},
|
|
1679
|
-
indentation: function() {return countColumn(this.string);},
|
|
2334
|
+
column: function() {return countColumn(this.string, this.start, this.tabSize);},
|
|
2335
|
+
indentation: function() {return countColumn(this.string, null, this.tabSize);},
|
|
1680
2336
|
match: function(pattern, consume, caseInsensitive) {
|
|
1681
2337
|
if (typeof pattern == "string") {
|
|
1682
|
-
|
|
2338
|
+
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
|
|
1683
2339
|
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
|
|
1684
2340
|
if (consume !== false) this.pos += pattern.length;
|
|
1685
2341
|
return true;
|
|
1686
2342
|
}
|
|
1687
|
-
}
|
|
1688
|
-
else {
|
|
2343
|
+
} else {
|
|
1689
2344
|
var match = this.string.slice(this.pos).match(pattern);
|
|
2345
|
+
if (match && match.index > 0) return null;
|
|
1690
2346
|
if (match && consume !== false) this.pos += match[0].length;
|
|
1691
2347
|
return match;
|
|
1692
2348
|
}
|
|
@@ -1695,71 +2351,162 @@ var CodeMirror = (function() {
|
|
|
1695
2351
|
};
|
|
1696
2352
|
CodeMirror.StringStream = StringStream;
|
|
1697
2353
|
|
|
2354
|
+
function MarkedSpan(from, to, marker) {
|
|
2355
|
+
this.from = from; this.to = to; this.marker = marker;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
function getMarkedSpanFor(spans, marker, del) {
|
|
2359
|
+
if (spans) for (var i = 0; i < spans.length; ++i) {
|
|
2360
|
+
var span = spans[i];
|
|
2361
|
+
if (span.marker == marker) {
|
|
2362
|
+
if (del) spans.splice(i, 1);
|
|
2363
|
+
return span;
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
function markedSpansBefore(old, startCh, endCh) {
|
|
2369
|
+
if (old) for (var i = 0, nw; i < old.length; ++i) {
|
|
2370
|
+
var span = old[i], marker = span.marker;
|
|
2371
|
+
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
|
|
2372
|
+
if (startsBefore || marker.type == "bookmark" && span.from == startCh && span.from != endCh) {
|
|
2373
|
+
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
|
|
2374
|
+
(nw || (nw = [])).push({from: span.from,
|
|
2375
|
+
to: endsAfter ? null : span.to,
|
|
2376
|
+
marker: marker});
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
return nw;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
function markedSpansAfter(old, endCh) {
|
|
2383
|
+
if (old) for (var i = 0, nw; i < old.length; ++i) {
|
|
2384
|
+
var span = old[i], marker = span.marker;
|
|
2385
|
+
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
|
|
2386
|
+
if (endsAfter || marker.type == "bookmark" && span.from == endCh) {
|
|
2387
|
+
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
|
|
2388
|
+
(nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
|
|
2389
|
+
to: span.to == null ? null : span.to - endCh,
|
|
2390
|
+
marker: marker});
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
return nw;
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
function updateMarkedSpans(oldFirst, oldLast, startCh, endCh, newText) {
|
|
2397
|
+
if (!oldFirst && !oldLast) return newText;
|
|
2398
|
+
// Get the spans that 'stick out' on both sides
|
|
2399
|
+
var first = markedSpansBefore(oldFirst, startCh);
|
|
2400
|
+
var last = markedSpansAfter(oldLast, endCh);
|
|
2401
|
+
|
|
2402
|
+
// Next, merge those two ends
|
|
2403
|
+
var sameLine = newText.length == 1, offset = lst(newText).length + (sameLine ? startCh : 0);
|
|
2404
|
+
if (first) {
|
|
2405
|
+
// Fix up .to properties of first
|
|
2406
|
+
for (var i = 0; i < first.length; ++i) {
|
|
2407
|
+
var span = first[i];
|
|
2408
|
+
if (span.to == null) {
|
|
2409
|
+
var found = getMarkedSpanFor(last, span.marker);
|
|
2410
|
+
if (!found) span.to = startCh;
|
|
2411
|
+
else if (sameLine) span.to = found.to == null ? null : found.to + offset;
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
if (last) {
|
|
2416
|
+
// Fix up .from in last (or move them into first in case of sameLine)
|
|
2417
|
+
for (var i = 0; i < last.length; ++i) {
|
|
2418
|
+
var span = last[i];
|
|
2419
|
+
if (span.to != null) span.to += offset;
|
|
2420
|
+
if (span.from == null) {
|
|
2421
|
+
var found = getMarkedSpanFor(first, span.marker);
|
|
2422
|
+
if (!found) {
|
|
2423
|
+
span.from = offset;
|
|
2424
|
+
if (sameLine) (first || (first = [])).push(span);
|
|
2425
|
+
}
|
|
2426
|
+
} else {
|
|
2427
|
+
span.from += offset;
|
|
2428
|
+
if (sameLine) (first || (first = [])).push(span);
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
var newMarkers = [newHL(newText[0], first)];
|
|
2434
|
+
if (!sameLine) {
|
|
2435
|
+
// Fill gap with whole-line-spans
|
|
2436
|
+
var gap = newText.length - 2, gapMarkers;
|
|
2437
|
+
if (gap > 0 && first)
|
|
2438
|
+
for (var i = 0; i < first.length; ++i)
|
|
2439
|
+
if (first[i].to == null)
|
|
2440
|
+
(gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker});
|
|
2441
|
+
for (var i = 0; i < gap; ++i)
|
|
2442
|
+
newMarkers.push(newHL(newText[i+1], gapMarkers));
|
|
2443
|
+
newMarkers.push(newHL(lst(newText), last));
|
|
2444
|
+
}
|
|
2445
|
+
return newMarkers;
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
// hl stands for history-line, a data structure that can be either a
|
|
2449
|
+
// string (line without markers) or a {text, markedSpans} object.
|
|
2450
|
+
function hlText(val) { return typeof val == "string" ? val : val.text; }
|
|
2451
|
+
function hlSpans(val) { return typeof val == "string" ? null : val.markedSpans; }
|
|
2452
|
+
function newHL(text, spans) { return spans ? {text: text, markedSpans: spans} : text; }
|
|
2453
|
+
|
|
2454
|
+
function detachMarkedSpans(line) {
|
|
2455
|
+
var spans = line.markedSpans;
|
|
2456
|
+
if (!spans) return;
|
|
2457
|
+
for (var i = 0; i < spans.length; ++i) {
|
|
2458
|
+
var lines = spans[i].marker.lines;
|
|
2459
|
+
var ix = indexOf(lines, line);
|
|
2460
|
+
lines.splice(ix, 1);
|
|
2461
|
+
}
|
|
2462
|
+
line.markedSpans = null;
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
function attachMarkedSpans(line, spans) {
|
|
2466
|
+
if (!spans) return;
|
|
2467
|
+
for (var i = 0; i < spans.length; ++i)
|
|
2468
|
+
var marker = spans[i].marker.lines.push(line);
|
|
2469
|
+
line.markedSpans = spans;
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
// When measuring the position of the end of a line, different
|
|
2473
|
+
// browsers require different approaches. If an empty span is added,
|
|
2474
|
+
// many browsers report bogus offsets. Of those, some (Webkit,
|
|
2475
|
+
// recent IE) will accept a space without moving the whole span to
|
|
2476
|
+
// the next line when wrapping it, others work with a zero-width
|
|
2477
|
+
// space.
|
|
2478
|
+
var eolSpanContent = " ";
|
|
2479
|
+
if (gecko || (ie && !ie_lt8)) eolSpanContent = "\u200b";
|
|
2480
|
+
else if (opera) eolSpanContent = "";
|
|
2481
|
+
|
|
1698
2482
|
// Line objects. These hold state related to a line, including
|
|
1699
2483
|
// highlighting info (the styles array).
|
|
1700
|
-
function Line(text,
|
|
1701
|
-
this.styles = styles || [text, null];
|
|
1702
|
-
this.stateAfter = null;
|
|
2484
|
+
function Line(text, markedSpans) {
|
|
1703
2485
|
this.text = text;
|
|
1704
|
-
this.
|
|
2486
|
+
this.height = 1;
|
|
2487
|
+
attachMarkedSpans(this, markedSpans);
|
|
1705
2488
|
}
|
|
1706
2489
|
Line.prototype = {
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
copyStyles(to, this.text.length, this.styles, st);
|
|
1713
|
-
this.styles = st;
|
|
1714
|
-
this.text = this.text.slice(0, from) + text + this.text.slice(to);
|
|
1715
|
-
this.stateAfter = null;
|
|
1716
|
-
if (mk) {
|
|
1717
|
-
var diff = text.length - (to - from), end = this.text.length;
|
|
1718
|
-
function fix(n) {return n <= Math.min(to, to + diff) ? n : n + diff;}
|
|
1719
|
-
for (var i = 0; i < mk.length; ++i) {
|
|
1720
|
-
var mark = mk[i], del = false;
|
|
1721
|
-
if (mark.from >= end) del = true;
|
|
1722
|
-
else {mark.from = fix(mark.from); if (mark.to != null) mark.to = fix(mark.to);}
|
|
1723
|
-
if (del || mark.from >= mark.to) {mk.splice(i, 1); i--;}
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
},
|
|
1727
|
-
// Split a line in two, again keeping styles intact.
|
|
1728
|
-
split: function(pos, textBefore) {
|
|
1729
|
-
var st = [textBefore, null];
|
|
1730
|
-
copyStyles(pos, this.text.length, this.styles, st);
|
|
1731
|
-
return new Line(textBefore + this.text.slice(pos), st);
|
|
1732
|
-
},
|
|
1733
|
-
addMark: function(from, to, style) {
|
|
1734
|
-
var mk = this.marked, mark = {from: from, to: to, style: style};
|
|
1735
|
-
if (this.marked == null) this.marked = [];
|
|
1736
|
-
this.marked.push(mark);
|
|
1737
|
-
this.marked.sort(function(a, b){return a.from - b.from;});
|
|
1738
|
-
return mark;
|
|
1739
|
-
},
|
|
1740
|
-
removeMark: function(mark) {
|
|
1741
|
-
var mk = this.marked;
|
|
1742
|
-
if (!mk) return;
|
|
1743
|
-
for (var i = 0; i < mk.length; ++i)
|
|
1744
|
-
if (mk[i] == mark) {mk.splice(i, 1); break;}
|
|
2490
|
+
update: function(text, markedSpans) {
|
|
2491
|
+
this.text = text;
|
|
2492
|
+
this.stateAfter = this.styles = null;
|
|
2493
|
+
detachMarkedSpans(this);
|
|
2494
|
+
attachMarkedSpans(this, markedSpans);
|
|
1745
2495
|
},
|
|
1746
2496
|
// Run the given mode's parser over a line, update the styles
|
|
1747
2497
|
// array, which contains alternating fragments of text and CSS
|
|
1748
2498
|
// classes.
|
|
1749
|
-
highlight: function(mode, state) {
|
|
1750
|
-
var stream = new StringStream(this.text), st = this.styles
|
|
1751
|
-
var
|
|
2499
|
+
highlight: function(mode, state, tabSize) {
|
|
2500
|
+
var stream = new StringStream(this.text, tabSize), st = this.styles || (this.styles = []);
|
|
2501
|
+
var pos = st.length = 0;
|
|
1752
2502
|
if (this.text == "" && mode.blankLine) mode.blankLine(state);
|
|
1753
2503
|
while (!stream.eol()) {
|
|
1754
|
-
var style = mode.token(stream, state);
|
|
1755
|
-
var substr = this.text.slice(stream.start, stream.pos);
|
|
2504
|
+
var style = mode.token(stream, state), substr = stream.current();
|
|
1756
2505
|
stream.start = stream.pos;
|
|
1757
|
-
if (pos && st[pos-1] == style)
|
|
2506
|
+
if (pos && st[pos-1] == style) {
|
|
1758
2507
|
st[pos-2] += substr;
|
|
1759
|
-
else if (substr) {
|
|
1760
|
-
if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true;
|
|
2508
|
+
} else if (substr) {
|
|
1761
2509
|
st[pos++] = substr; st[pos++] = style;
|
|
1762
|
-
prevWord = curWord; curWord = st[pos];
|
|
1763
2510
|
}
|
|
1764
2511
|
// Give up when line is ridiculously long
|
|
1765
2512
|
if (stream.pos > 5000) {
|
|
@@ -1767,17 +2514,19 @@ var CodeMirror = (function() {
|
|
|
1767
2514
|
break;
|
|
1768
2515
|
}
|
|
1769
2516
|
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
2517
|
+
},
|
|
2518
|
+
process: function(mode, state, tabSize) {
|
|
2519
|
+
var stream = new StringStream(this.text, tabSize);
|
|
2520
|
+
if (this.text == "" && mode.blankLine) mode.blankLine(state);
|
|
2521
|
+
while (!stream.eol() && stream.pos <= 5000) {
|
|
2522
|
+
mode.token(stream, state);
|
|
2523
|
+
stream.start = stream.pos;
|
|
2524
|
+
}
|
|
1776
2525
|
},
|
|
1777
2526
|
// Fetch the parser token for a given character. Useful for hacks
|
|
1778
2527
|
// that want to inspect the mode state (say, for completion).
|
|
1779
|
-
getTokenAt: function(mode, state, ch) {
|
|
1780
|
-
var txt = this.text, stream = new StringStream(txt);
|
|
2528
|
+
getTokenAt: function(mode, state, tabSize, ch) {
|
|
2529
|
+
var txt = this.text, stream = new StringStream(txt, tabSize);
|
|
1781
2530
|
while (stream.pos < ch && !stream.eol()) {
|
|
1782
2531
|
stream.start = stream.pos;
|
|
1783
2532
|
var style = mode.token(stream, state);
|
|
@@ -1788,90 +2537,327 @@ var CodeMirror = (function() {
|
|
|
1788
2537
|
className: style || null,
|
|
1789
2538
|
state: state};
|
|
1790
2539
|
},
|
|
1791
|
-
indentation: function() {return countColumn(this.text);},
|
|
2540
|
+
indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
|
|
1792
2541
|
// Produces an HTML fragment for the line, taking selection,
|
|
1793
2542
|
// marking, and highlighting into account.
|
|
1794
|
-
|
|
1795
|
-
var
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
function span(text, style) {
|
|
2543
|
+
getContent: function(tabSize, wrapAt, compensateForWrapping) {
|
|
2544
|
+
var first = true, col = 0, specials = /[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]/g;
|
|
2545
|
+
var pre = elt("pre");
|
|
2546
|
+
function span_(html, text, style) {
|
|
1799
2547
|
if (!text) return;
|
|
1800
|
-
|
|
1801
|
-
|
|
2548
|
+
// Work around a bug where, in some compat modes, IE ignores leading spaces
|
|
2549
|
+
if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
|
|
2550
|
+
first = false;
|
|
2551
|
+
if (!specials.test(text)) {
|
|
2552
|
+
col += text.length;
|
|
2553
|
+
var content = document.createTextNode(text);
|
|
2554
|
+
} else {
|
|
2555
|
+
var content = document.createDocumentFragment(), pos = 0;
|
|
2556
|
+
while (true) {
|
|
2557
|
+
specials.lastIndex = pos;
|
|
2558
|
+
var m = specials.exec(text);
|
|
2559
|
+
var skipped = m ? m.index - pos : text.length - pos;
|
|
2560
|
+
if (skipped) {
|
|
2561
|
+
content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
|
|
2562
|
+
col += skipped;
|
|
2563
|
+
}
|
|
2564
|
+
if (!m) break;
|
|
2565
|
+
pos += skipped + 1;
|
|
2566
|
+
if (m[0] == "\t") {
|
|
2567
|
+
var tabWidth = tabSize - col % tabSize;
|
|
2568
|
+
content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
|
|
2569
|
+
col += tabWidth;
|
|
2570
|
+
} else {
|
|
2571
|
+
var token = elt("span", "\u2022", "cm-invalidchar");
|
|
2572
|
+
token.title = "\\u" + m[0].charCodeAt(0).toString(16);
|
|
2573
|
+
content.appendChild(token);
|
|
2574
|
+
col += 1;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
if (style) html.appendChild(elt("span", [content], style));
|
|
2579
|
+
else html.appendChild(content);
|
|
2580
|
+
}
|
|
2581
|
+
var span = span_;
|
|
2582
|
+
if (wrapAt != null) {
|
|
2583
|
+
var outPos = 0, anchor = pre.anchor = elt("span");
|
|
2584
|
+
span = function(html, text, style) {
|
|
2585
|
+
var l = text.length;
|
|
2586
|
+
if (wrapAt >= outPos && wrapAt < outPos + l) {
|
|
2587
|
+
if (wrapAt > outPos) {
|
|
2588
|
+
span_(html, text.slice(0, wrapAt - outPos), style);
|
|
2589
|
+
// See comment at the definition of spanAffectsWrapping
|
|
2590
|
+
if (compensateForWrapping) html.appendChild(elt("wbr"));
|
|
2591
|
+
}
|
|
2592
|
+
html.appendChild(anchor);
|
|
2593
|
+
var cut = wrapAt - outPos;
|
|
2594
|
+
span_(anchor, opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
|
|
2595
|
+
if (opera) span_(html, text.slice(cut + 1), style);
|
|
2596
|
+
wrapAt--;
|
|
2597
|
+
outPos += l;
|
|
2598
|
+
} else {
|
|
2599
|
+
outPos += l;
|
|
2600
|
+
span_(html, text, style);
|
|
2601
|
+
if (outPos == wrapAt && outPos == len) {
|
|
2602
|
+
setTextContent(anchor, eolSpanContent);
|
|
2603
|
+
html.appendChild(anchor);
|
|
2604
|
+
}
|
|
2605
|
+
// Stop outputting HTML when gone sufficiently far beyond measure
|
|
2606
|
+
else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
|
|
2607
|
+
}
|
|
2608
|
+
};
|
|
1802
2609
|
}
|
|
1803
|
-
var st = this.styles, allText = this.text, marked = this.marked;
|
|
1804
|
-
if (sfrom == sto) sfrom = null;
|
|
1805
|
-
var len = allText.length;
|
|
1806
|
-
if (endAt != null) len = Math.min(endAt, len);
|
|
1807
2610
|
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
2611
|
+
var st = this.styles, allText = this.text, marked = this.markedSpans;
|
|
2612
|
+
var len = allText.length;
|
|
2613
|
+
function styleToClass(style) {
|
|
2614
|
+
if (!style) return null;
|
|
2615
|
+
return "cm-" + style.replace(/ +/g, " cm-");
|
|
2616
|
+
}
|
|
2617
|
+
if (!allText && wrapAt == null) {
|
|
2618
|
+
span(pre, " ");
|
|
2619
|
+
} else if (!marked || !marked.length) {
|
|
1811
2620
|
for (var i = 0, ch = 0; ch < len; i+=2) {
|
|
1812
|
-
var str = st[i], l = str.length;
|
|
2621
|
+
var str = st[i], style = st[i+1], l = str.length;
|
|
1813
2622
|
if (ch + l > len) str = str.slice(0, len - ch);
|
|
1814
2623
|
ch += l;
|
|
1815
|
-
span(str,
|
|
2624
|
+
span(pre, str, styleToClass(style));
|
|
1816
2625
|
}
|
|
1817
|
-
else {
|
|
2626
|
+
} else {
|
|
2627
|
+
marked.sort(function(a, b) { return a.from - b.from; });
|
|
1818
2628
|
var pos = 0, i = 0, text = "", style, sg = 0;
|
|
1819
|
-
var
|
|
1820
|
-
function
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
2629
|
+
var nextChange = marked[0].from || 0, marks = [], markpos = 0;
|
|
2630
|
+
var advanceMarks = function() {
|
|
2631
|
+
var m;
|
|
2632
|
+
while (markpos < marked.length &&
|
|
2633
|
+
((m = marked[markpos]).from == pos || m.from == null)) {
|
|
2634
|
+
if (m.marker.type == "range") marks.push(m);
|
|
2635
|
+
++markpos;
|
|
1824
2636
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
2637
|
+
nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
|
|
2638
|
+
for (var i = 0; i < marks.length; ++i) {
|
|
2639
|
+
var to = marks[i].to;
|
|
2640
|
+
if (to == null) to = Infinity;
|
|
2641
|
+
if (to == pos) marks.splice(i--, 1);
|
|
2642
|
+
else nextChange = Math.min(to, nextChange);
|
|
2643
|
+
}
|
|
2644
|
+
};
|
|
2645
|
+
var m = 0;
|
|
1827
2646
|
while (pos < len) {
|
|
1828
|
-
|
|
1829
|
-
var
|
|
1830
|
-
|
|
1831
|
-
if (
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
2647
|
+
if (nextChange == pos) advanceMarks();
|
|
2648
|
+
var upto = Math.min(len, nextChange);
|
|
2649
|
+
while (true) {
|
|
2650
|
+
if (text) {
|
|
2651
|
+
var end = pos + text.length;
|
|
2652
|
+
var appliedStyle = style;
|
|
2653
|
+
for (var j = 0; j < marks.length; ++j) {
|
|
2654
|
+
var mark = marks[j];
|
|
2655
|
+
appliedStyle = (appliedStyle ? appliedStyle + " " : "") + mark.marker.style;
|
|
2656
|
+
if (mark.marker.endStyle && mark.to === Math.min(end, upto)) appliedStyle += " " + mark.marker.endStyle;
|
|
2657
|
+
if (mark.marker.startStyle && mark.from === pos) appliedStyle += " " + mark.marker.startStyle;
|
|
2658
|
+
}
|
|
2659
|
+
span(pre, end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
|
|
2660
|
+
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
|
|
2661
|
+
pos = end;
|
|
1835
2662
|
}
|
|
2663
|
+
text = st[i++]; style = styleToClass(st[i++]);
|
|
1836
2664
|
}
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
return pre;
|
|
2668
|
+
},
|
|
2669
|
+
cleanUp: function() {
|
|
2670
|
+
this.parent = null;
|
|
2671
|
+
detachMarkedSpans(this);
|
|
2672
|
+
}
|
|
2673
|
+
};
|
|
2674
|
+
|
|
2675
|
+
// Data structure that holds the sequence of lines.
|
|
2676
|
+
function LeafChunk(lines) {
|
|
2677
|
+
this.lines = lines;
|
|
2678
|
+
this.parent = null;
|
|
2679
|
+
for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
|
|
2680
|
+
lines[i].parent = this;
|
|
2681
|
+
height += lines[i].height;
|
|
2682
|
+
}
|
|
2683
|
+
this.height = height;
|
|
2684
|
+
}
|
|
2685
|
+
LeafChunk.prototype = {
|
|
2686
|
+
chunkSize: function() { return this.lines.length; },
|
|
2687
|
+
remove: function(at, n, callbacks) {
|
|
2688
|
+
for (var i = at, e = at + n; i < e; ++i) {
|
|
2689
|
+
var line = this.lines[i];
|
|
2690
|
+
this.height -= line.height;
|
|
2691
|
+
line.cleanUp();
|
|
2692
|
+
if (line.handlers)
|
|
2693
|
+
for (var j = 0; j < line.handlers.length; ++j) callbacks.push(line.handlers[j]);
|
|
2694
|
+
}
|
|
2695
|
+
this.lines.splice(at, n);
|
|
2696
|
+
},
|
|
2697
|
+
collapse: function(lines) {
|
|
2698
|
+
lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
|
|
2699
|
+
},
|
|
2700
|
+
insertHeight: function(at, lines, height) {
|
|
2701
|
+
this.height += height;
|
|
2702
|
+
this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
|
|
2703
|
+
for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
|
|
2704
|
+
},
|
|
2705
|
+
iterN: function(at, n, op) {
|
|
2706
|
+
for (var e = at + n; at < e; ++at)
|
|
2707
|
+
if (op(this.lines[at])) return true;
|
|
2708
|
+
}
|
|
2709
|
+
};
|
|
2710
|
+
function BranchChunk(children) {
|
|
2711
|
+
this.children = children;
|
|
2712
|
+
var size = 0, height = 0;
|
|
2713
|
+
for (var i = 0, e = children.length; i < e; ++i) {
|
|
2714
|
+
var ch = children[i];
|
|
2715
|
+
size += ch.chunkSize(); height += ch.height;
|
|
2716
|
+
ch.parent = this;
|
|
2717
|
+
}
|
|
2718
|
+
this.size = size;
|
|
2719
|
+
this.height = height;
|
|
2720
|
+
this.parent = null;
|
|
2721
|
+
}
|
|
2722
|
+
BranchChunk.prototype = {
|
|
2723
|
+
chunkSize: function() { return this.size; },
|
|
2724
|
+
remove: function(at, n, callbacks) {
|
|
2725
|
+
this.size -= n;
|
|
2726
|
+
for (var i = 0; i < this.children.length; ++i) {
|
|
2727
|
+
var child = this.children[i], sz = child.chunkSize();
|
|
2728
|
+
if (at < sz) {
|
|
2729
|
+
var rm = Math.min(n, sz - at), oldHeight = child.height;
|
|
2730
|
+
child.remove(at, rm, callbacks);
|
|
2731
|
+
this.height -= oldHeight - child.height;
|
|
2732
|
+
if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
|
|
2733
|
+
if ((n -= rm) == 0) break;
|
|
2734
|
+
at = 0;
|
|
2735
|
+
} else at -= sz;
|
|
2736
|
+
}
|
|
2737
|
+
if (this.size - n < 25) {
|
|
2738
|
+
var lines = [];
|
|
2739
|
+
this.collapse(lines);
|
|
2740
|
+
this.children = [new LeafChunk(lines)];
|
|
2741
|
+
this.children[0].parent = this;
|
|
2742
|
+
}
|
|
2743
|
+
},
|
|
2744
|
+
collapse: function(lines) {
|
|
2745
|
+
for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
|
|
2746
|
+
},
|
|
2747
|
+
insert: function(at, lines) {
|
|
2748
|
+
var height = 0;
|
|
2749
|
+
for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
|
|
2750
|
+
this.insertHeight(at, lines, height);
|
|
2751
|
+
},
|
|
2752
|
+
insertHeight: function(at, lines, height) {
|
|
2753
|
+
this.size += lines.length;
|
|
2754
|
+
this.height += height;
|
|
2755
|
+
for (var i = 0, e = this.children.length; i < e; ++i) {
|
|
2756
|
+
var child = this.children[i], sz = child.chunkSize();
|
|
2757
|
+
if (at <= sz) {
|
|
2758
|
+
child.insertHeight(at, lines, height);
|
|
2759
|
+
if (child.lines && child.lines.length > 50) {
|
|
2760
|
+
while (child.lines.length > 50) {
|
|
2761
|
+
var spilled = child.lines.splice(child.lines.length - 25, 25);
|
|
2762
|
+
var newleaf = new LeafChunk(spilled);
|
|
2763
|
+
child.height -= newleaf.height;
|
|
2764
|
+
this.children.splice(i + 1, 0, newleaf);
|
|
2765
|
+
newleaf.parent = this;
|
|
1843
2766
|
}
|
|
2767
|
+
this.maybeSpill();
|
|
1844
2768
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
2769
|
+
break;
|
|
2770
|
+
}
|
|
2771
|
+
at -= sz;
|
|
2772
|
+
}
|
|
2773
|
+
},
|
|
2774
|
+
maybeSpill: function() {
|
|
2775
|
+
if (this.children.length <= 10) return;
|
|
2776
|
+
var me = this;
|
|
2777
|
+
do {
|
|
2778
|
+
var spilled = me.children.splice(me.children.length - 5, 5);
|
|
2779
|
+
var sibling = new BranchChunk(spilled);
|
|
2780
|
+
if (!me.parent) { // Become the parent node
|
|
2781
|
+
var copy = new BranchChunk(me.children);
|
|
2782
|
+
copy.parent = me;
|
|
2783
|
+
me.children = [copy, sibling];
|
|
2784
|
+
me = copy;
|
|
2785
|
+
} else {
|
|
2786
|
+
me.size -= sibling.size;
|
|
2787
|
+
me.height -= sibling.height;
|
|
2788
|
+
var myIndex = indexOf(me.parent.children, me);
|
|
2789
|
+
me.parent.children.splice(myIndex + 1, 0, sibling);
|
|
1854
2790
|
}
|
|
1855
|
-
|
|
2791
|
+
sibling.parent = me.parent;
|
|
2792
|
+
} while (me.children.length > 10);
|
|
2793
|
+
me.parent.maybeSpill();
|
|
2794
|
+
},
|
|
2795
|
+
iter: function(from, to, op) { this.iterN(from, to - from, op); },
|
|
2796
|
+
iterN: function(at, n, op) {
|
|
2797
|
+
for (var i = 0, e = this.children.length; i < e; ++i) {
|
|
2798
|
+
var child = this.children[i], sz = child.chunkSize();
|
|
2799
|
+
if (at < sz) {
|
|
2800
|
+
var used = Math.min(n, sz - at);
|
|
2801
|
+
if (child.iterN(at, used, op)) return true;
|
|
2802
|
+
if ((n -= used) == 0) break;
|
|
2803
|
+
at = 0;
|
|
2804
|
+
} else at -= sz;
|
|
1856
2805
|
}
|
|
1857
|
-
if (includePre) html.push("</pre>");
|
|
1858
|
-
return html.join("");
|
|
1859
2806
|
}
|
|
1860
2807
|
};
|
|
1861
|
-
|
|
1862
|
-
function
|
|
1863
|
-
|
|
1864
|
-
var
|
|
1865
|
-
|
|
1866
|
-
if (
|
|
1867
|
-
|
|
2808
|
+
|
|
2809
|
+
function getLineAt(chunk, n) {
|
|
2810
|
+
while (!chunk.lines) {
|
|
2811
|
+
for (var i = 0;; ++i) {
|
|
2812
|
+
var child = chunk.children[i], sz = child.chunkSize();
|
|
2813
|
+
if (n < sz) { chunk = child; break; }
|
|
2814
|
+
n -= sz;
|
|
1868
2815
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
2816
|
+
}
|
|
2817
|
+
return chunk.lines[n];
|
|
2818
|
+
}
|
|
2819
|
+
function lineNo(line) {
|
|
2820
|
+
if (line.parent == null) return null;
|
|
2821
|
+
var cur = line.parent, no = indexOf(cur.lines, line);
|
|
2822
|
+
for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
|
|
2823
|
+
for (var i = 0, e = chunk.children.length; ; ++i) {
|
|
2824
|
+
if (chunk.children[i] == cur) break;
|
|
2825
|
+
no += chunk.children[i].chunkSize();
|
|
1872
2826
|
}
|
|
1873
|
-
pos = end;
|
|
1874
2827
|
}
|
|
2828
|
+
return no;
|
|
2829
|
+
}
|
|
2830
|
+
function lineAtHeight(chunk, h) {
|
|
2831
|
+
var n = 0;
|
|
2832
|
+
outer: do {
|
|
2833
|
+
for (var i = 0, e = chunk.children.length; i < e; ++i) {
|
|
2834
|
+
var child = chunk.children[i], ch = child.height;
|
|
2835
|
+
if (h < ch) { chunk = child; continue outer; }
|
|
2836
|
+
h -= ch;
|
|
2837
|
+
n += child.chunkSize();
|
|
2838
|
+
}
|
|
2839
|
+
return n;
|
|
2840
|
+
} while (!chunk.lines);
|
|
2841
|
+
for (var i = 0, e = chunk.lines.length; i < e; ++i) {
|
|
2842
|
+
var line = chunk.lines[i], lh = line.height;
|
|
2843
|
+
if (h < lh) break;
|
|
2844
|
+
h -= lh;
|
|
2845
|
+
}
|
|
2846
|
+
return n + i;
|
|
2847
|
+
}
|
|
2848
|
+
function heightAtLine(chunk, n) {
|
|
2849
|
+
var h = 0;
|
|
2850
|
+
outer: do {
|
|
2851
|
+
for (var i = 0, e = chunk.children.length; i < e; ++i) {
|
|
2852
|
+
var child = chunk.children[i], sz = child.chunkSize();
|
|
2853
|
+
if (n < sz) { chunk = child; continue outer; }
|
|
2854
|
+
n -= sz;
|
|
2855
|
+
h += child.height;
|
|
2856
|
+
}
|
|
2857
|
+
return h;
|
|
2858
|
+
} while (!chunk.lines);
|
|
2859
|
+
for (var i = 0; i < n; ++i) h += chunk.lines[i].height;
|
|
2860
|
+
return h;
|
|
1875
2861
|
}
|
|
1876
2862
|
|
|
1877
2863
|
// The history object 'chunks' changes that are made close together
|
|
@@ -1879,31 +2865,36 @@ var CodeMirror = (function() {
|
|
|
1879
2865
|
function History() {
|
|
1880
2866
|
this.time = 0;
|
|
1881
2867
|
this.done = []; this.undone = [];
|
|
2868
|
+
this.compound = 0;
|
|
2869
|
+
this.closed = false;
|
|
1882
2870
|
}
|
|
1883
2871
|
History.prototype = {
|
|
1884
2872
|
addChange: function(start, added, old) {
|
|
1885
2873
|
this.undone.length = 0;
|
|
1886
|
-
var time = +new Date,
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
for (var i = last.added - oldoff, e = old.length; i < e; ++i)
|
|
1903
|
-
last.old.push(old[i]);
|
|
1904
|
-
if (last.added < added) last.added = added;
|
|
2874
|
+
var time = +new Date, cur = lst(this.done), last = cur && lst(cur);
|
|
2875
|
+
var dtime = time - this.time;
|
|
2876
|
+
|
|
2877
|
+
if (this.compound && cur && !this.closed) {
|
|
2878
|
+
cur.push({start: start, added: added, old: old});
|
|
2879
|
+
} else if (dtime > 400 || !last || this.closed ||
|
|
2880
|
+
last.start > start + old.length || last.start + last.added < start) {
|
|
2881
|
+
this.done.push([{start: start, added: added, old: old}]);
|
|
2882
|
+
this.closed = false;
|
|
2883
|
+
} else {
|
|
2884
|
+
var startBefore = Math.max(0, last.start - start),
|
|
2885
|
+
endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
|
|
2886
|
+
for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
|
|
2887
|
+
for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
|
|
2888
|
+
if (startBefore) last.start = start;
|
|
2889
|
+
last.added += added - (old.length - startBefore - endAfter);
|
|
1905
2890
|
}
|
|
1906
2891
|
this.time = time;
|
|
2892
|
+
},
|
|
2893
|
+
startCompound: function() {
|
|
2894
|
+
if (!this.compound++) this.closed = true;
|
|
2895
|
+
},
|
|
2896
|
+
endCompound: function() {
|
|
2897
|
+
if (!--this.compound) this.closed = true;
|
|
1907
2898
|
}
|
|
1908
2899
|
};
|
|
1909
2900
|
|
|
@@ -1923,69 +2914,80 @@ var CodeMirror = (function() {
|
|
|
1923
2914
|
else e.cancelBubble = true;
|
|
1924
2915
|
}
|
|
1925
2916
|
function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
|
|
2917
|
+
CodeMirror.e_stop = e_stop;
|
|
2918
|
+
CodeMirror.e_preventDefault = e_preventDefault;
|
|
2919
|
+
CodeMirror.e_stopPropagation = e_stopPropagation;
|
|
2920
|
+
|
|
1926
2921
|
function e_target(e) {return e.target || e.srcElement;}
|
|
1927
2922
|
function e_button(e) {
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
2923
|
+
var b = e.which;
|
|
2924
|
+
if (b == null) {
|
|
2925
|
+
if (e.button & 1) b = 1;
|
|
2926
|
+
else if (e.button & 2) b = 3;
|
|
2927
|
+
else if (e.button & 4) b = 2;
|
|
2928
|
+
}
|
|
2929
|
+
if (mac && e.ctrlKey && b == 1) b = 3;
|
|
2930
|
+
return b;
|
|
1932
2931
|
}
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
if (e.pageY != null) return e.pageY;
|
|
1940
|
-
var doc = e_target(e).ownerDocument;
|
|
1941
|
-
return e.clientY + doc.body.scrollTop + doc.documentElement.scrollTop;
|
|
2932
|
+
|
|
2933
|
+
// Allow 3rd-party code to override event properties by adding an override
|
|
2934
|
+
// object to an event object.
|
|
2935
|
+
function e_prop(e, prop) {
|
|
2936
|
+
var overridden = e.override && e.override.hasOwnProperty(prop);
|
|
2937
|
+
return overridden ? e.override[prop] : e[prop];
|
|
1942
2938
|
}
|
|
1943
2939
|
|
|
1944
2940
|
// Event handler registration. If disconnect is true, it'll return a
|
|
1945
2941
|
// function that unregisters the handler.
|
|
1946
2942
|
function connect(node, type, handler, disconnect) {
|
|
1947
|
-
function wrapHandler(event) {handler(event || window.event);}
|
|
1948
2943
|
if (typeof node.addEventListener == "function") {
|
|
1949
|
-
node.addEventListener(type,
|
|
1950
|
-
if (disconnect) return function() {node.removeEventListener(type,
|
|
1951
|
-
}
|
|
1952
|
-
|
|
2944
|
+
node.addEventListener(type, handler, false);
|
|
2945
|
+
if (disconnect) return function() {node.removeEventListener(type, handler, false);};
|
|
2946
|
+
} else {
|
|
2947
|
+
var wrapHandler = function(event) {handler(event || window.event);};
|
|
1953
2948
|
node.attachEvent("on" + type, wrapHandler);
|
|
1954
2949
|
if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
|
|
1955
2950
|
}
|
|
1956
2951
|
}
|
|
2952
|
+
CodeMirror.connect = connect;
|
|
1957
2953
|
|
|
1958
2954
|
function Delayed() {this.id = null;}
|
|
1959
2955
|
Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
|
|
1960
2956
|
|
|
1961
|
-
|
|
1962
|
-
// innerHTML of a PRE tag.
|
|
1963
|
-
var badInnerHTML = (function() {
|
|
1964
|
-
var pre = document.createElement("pre");
|
|
1965
|
-
pre.innerHTML = " "; return !pre.innerHTML;
|
|
1966
|
-
})();
|
|
2957
|
+
var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
|
|
1967
2958
|
|
|
1968
|
-
|
|
1969
|
-
var
|
|
1970
|
-
|
|
2959
|
+
// Detect drag-and-drop
|
|
2960
|
+
var dragAndDrop = function() {
|
|
2961
|
+
// There is *some* kind of drag-and-drop support in IE6-8, but I
|
|
2962
|
+
// couldn't get it to work yet.
|
|
2963
|
+
if (ie_lt9) return false;
|
|
2964
|
+
var div = elt('div');
|
|
2965
|
+
return "draggable" in div || "dragDrop" in div;
|
|
2966
|
+
}();
|
|
1971
2967
|
|
|
1972
|
-
var lineSep = "\n";
|
|
1973
2968
|
// Feature-detect whether newlines in textareas are converted to \r\n
|
|
1974
|
-
|
|
1975
|
-
var te =
|
|
2969
|
+
var lineSep = function () {
|
|
2970
|
+
var te = elt("textarea");
|
|
1976
2971
|
te.value = "foo\nbar";
|
|
1977
|
-
if (te.value.indexOf("\r") > -1)
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
2972
|
+
if (te.value.indexOf("\r") > -1) return "\r\n";
|
|
2973
|
+
return "\n";
|
|
2974
|
+
}();
|
|
2975
|
+
|
|
2976
|
+
// For a reason I have yet to figure out, some browsers disallow
|
|
2977
|
+
// word wrapping between certain characters *only* if a new inline
|
|
2978
|
+
// element is started between them. This makes it hard to reliably
|
|
2979
|
+
// measure the position of things, since that requires inserting an
|
|
2980
|
+
// extra span. This terribly fragile set of regexps matches the
|
|
2981
|
+
// character combinations that suffer from this phenomenon on the
|
|
2982
|
+
// various browsers.
|
|
2983
|
+
var spanAffectsWrapping = /^$/; // Won't match any two-character string
|
|
2984
|
+
if (gecko) spanAffectsWrapping = /$'/;
|
|
2985
|
+
else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
|
|
2986
|
+
else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
|
|
1985
2987
|
|
|
1986
2988
|
// Counts the column offset in a string, taking tabs into account.
|
|
1987
2989
|
// Used mostly to find indentation.
|
|
1988
|
-
function countColumn(string, end) {
|
|
2990
|
+
function countColumn(string, end, tabSize) {
|
|
1989
2991
|
if (end == null) {
|
|
1990
2992
|
end = string.search(/[^\s\u00a0]/);
|
|
1991
2993
|
if (end == -1) end = string.length;
|
|
@@ -1997,46 +2999,75 @@ var CodeMirror = (function() {
|
|
|
1997
2999
|
return n;
|
|
1998
3000
|
}
|
|
1999
3001
|
|
|
2000
|
-
function computedStyle(elt) {
|
|
2001
|
-
if (elt.currentStyle) return elt.currentStyle;
|
|
2002
|
-
return window.getComputedStyle(elt, null);
|
|
2003
|
-
}
|
|
2004
|
-
// Find the position of an element by following the offsetParent chain.
|
|
2005
|
-
// If screen==true, it returns screen (rather than page) coordinates.
|
|
2006
3002
|
function eltOffset(node, screen) {
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
3003
|
+
// Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
|
|
3004
|
+
// since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
|
|
3005
|
+
try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
|
|
3006
|
+
catch(e) { box = {top: 0, left: 0}; }
|
|
3007
|
+
if (!screen) {
|
|
3008
|
+
// Get the toplevel scroll, working around browser differences.
|
|
3009
|
+
if (window.pageYOffset == null) {
|
|
3010
|
+
var t = document.documentElement || document.body.parentNode;
|
|
3011
|
+
if (t.scrollTop == null) t = document.body;
|
|
3012
|
+
box.top += t.scrollTop; box.left += t.scrollLeft;
|
|
3013
|
+
} else {
|
|
3014
|
+
box.top += window.pageYOffset; box.left += window.pageXOffset;
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
return box;
|
|
2018
3018
|
}
|
|
2019
|
-
|
|
3019
|
+
|
|
2020
3020
|
function eltText(node) {
|
|
2021
3021
|
return node.textContent || node.innerText || node.nodeValue || "";
|
|
2022
3022
|
}
|
|
2023
3023
|
|
|
3024
|
+
var spaceStrs = [""];
|
|
3025
|
+
function spaceStr(n) {
|
|
3026
|
+
while (spaceStrs.length <= n)
|
|
3027
|
+
spaceStrs.push(lst(spaceStrs) + " ");
|
|
3028
|
+
return spaceStrs[n];
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
function lst(arr) { return arr[arr.length-1]; }
|
|
3032
|
+
|
|
3033
|
+
function selectInput(node) {
|
|
3034
|
+
if (ios) { // Mobile Safari apparently has a bug where select() is broken.
|
|
3035
|
+
node.selectionStart = 0;
|
|
3036
|
+
node.selectionEnd = node.value.length;
|
|
3037
|
+
} else node.select();
|
|
3038
|
+
}
|
|
3039
|
+
|
|
2024
3040
|
// Operations on {line, ch} objects.
|
|
2025
3041
|
function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
|
|
2026
3042
|
function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
|
|
2027
3043
|
function copyPos(x) {return {line: x.line, ch: x.ch};}
|
|
2028
3044
|
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
3045
|
+
function elt(tag, content, className, style) {
|
|
3046
|
+
var e = document.createElement(tag);
|
|
3047
|
+
if (className) e.className = className;
|
|
3048
|
+
if (style) e.style.cssText = style;
|
|
3049
|
+
if (typeof content == "string") setTextContent(e, content);
|
|
3050
|
+
else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
|
|
3051
|
+
return e;
|
|
3052
|
+
}
|
|
3053
|
+
function removeChildren(e) {
|
|
3054
|
+
e.innerHTML = "";
|
|
3055
|
+
return e;
|
|
3056
|
+
}
|
|
3057
|
+
function removeChildrenAndAdd(parent, e) {
|
|
3058
|
+
removeChildren(parent).appendChild(e);
|
|
3059
|
+
}
|
|
3060
|
+
function setTextContent(e, str) {
|
|
3061
|
+
if (ie_lt9) {
|
|
3062
|
+
e.innerHTML = "";
|
|
3063
|
+
e.appendChild(document.createTextNode(str));
|
|
3064
|
+
} else e.textContent = str;
|
|
2033
3065
|
}
|
|
2034
|
-
CodeMirror.htmlEscape = htmlEscape;
|
|
2035
3066
|
|
|
2036
3067
|
// Used to position the cursor after an undo/redo by finding the
|
|
2037
3068
|
// last edited character.
|
|
2038
3069
|
function editEnd(from, to) {
|
|
2039
|
-
if (!to) return
|
|
3070
|
+
if (!to) return 0;
|
|
2040
3071
|
if (!from) return to.length;
|
|
2041
3072
|
for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
|
|
2042
3073
|
if (from.charAt(i) != to.charAt(j)) break;
|
|
@@ -2049,96 +3080,64 @@ var CodeMirror = (function() {
|
|
|
2049
3080
|
if (collection[i] == elt) return i;
|
|
2050
3081
|
return -1;
|
|
2051
3082
|
}
|
|
3083
|
+
function isWordChar(ch) {
|
|
3084
|
+
return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase();
|
|
3085
|
+
}
|
|
2052
3086
|
|
|
2053
3087
|
// See if "".split is the broken IE version, if so, provide an
|
|
2054
3088
|
// alternative way to split lines.
|
|
2055
|
-
var splitLines
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
var
|
|
2059
|
-
|
|
2060
|
-
|
|
3089
|
+
var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
|
|
3090
|
+
var pos = 0, result = [], l = string.length;
|
|
3091
|
+
while (pos <= l) {
|
|
3092
|
+
var nl = string.indexOf("\n", pos);
|
|
3093
|
+
if (nl == -1) nl = string.length;
|
|
3094
|
+
var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
|
|
3095
|
+
var rt = line.indexOf("\r");
|
|
3096
|
+
if (rt != -1) {
|
|
3097
|
+
result.push(line.slice(0, rt));
|
|
3098
|
+
pos += rt + 1;
|
|
3099
|
+
} else {
|
|
3100
|
+
result.push(line);
|
|
2061
3101
|
pos = nl + 1;
|
|
2062
3102
|
}
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
else
|
|
2067
|
-
splitLines = function(string){return string.split(/\r?\n/);};
|
|
3103
|
+
}
|
|
3104
|
+
return result;
|
|
3105
|
+
} : function(string){return string.split(/\r\n?|\n/);};
|
|
2068
3106
|
CodeMirror.splitLines = splitLines;
|
|
2069
3107
|
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
}
|
|
2076
|
-
if (
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
// the anchor is put at the end, and the selection expanded to
|
|
2080
|
-
// the left. If you press shift-right, the anchor ends up at the
|
|
2081
|
-
// front. This is not what CodeMirror wants, so it does a
|
|
2082
|
-
// spurious modify() call to get out of limbo.
|
|
2083
|
-
setSelRange = function(te, start, end) {
|
|
2084
|
-
if (start == end)
|
|
2085
|
-
te.setSelectionRange(start, end);
|
|
2086
|
-
else {
|
|
2087
|
-
te.setSelectionRange(start, end - 1);
|
|
2088
|
-
window.getSelection().modify("extend", "forward", "character");
|
|
2089
|
-
}
|
|
2090
|
-
};
|
|
2091
|
-
else
|
|
2092
|
-
setSelRange = function(te, start, end) {
|
|
2093
|
-
try {te.setSelectionRange(start, end);}
|
|
2094
|
-
catch(e) {} // Fails on Firefox when textarea isn't part of the document
|
|
2095
|
-
};
|
|
2096
|
-
}
|
|
2097
|
-
// IE model. Don't ask.
|
|
2098
|
-
else {
|
|
2099
|
-
selRange = function(te) {
|
|
2100
|
-
try {var range = te.ownerDocument.selection.createRange();}
|
|
2101
|
-
catch(e) {return null;}
|
|
2102
|
-
if (!range || range.parentElement() != te) return null;
|
|
2103
|
-
var val = te.value, len = val.length, localRange = te.createTextRange();
|
|
2104
|
-
localRange.moveToBookmark(range.getBookmark());
|
|
2105
|
-
var endRange = te.createTextRange();
|
|
2106
|
-
endRange.collapse(false);
|
|
2107
|
-
|
|
2108
|
-
if (localRange.compareEndPoints("StartToEnd", endRange) > -1)
|
|
2109
|
-
return {start: len, end: len};
|
|
2110
|
-
|
|
2111
|
-
var start = -localRange.moveStart("character", -len);
|
|
2112
|
-
for (var i = val.indexOf("\r"); i > -1 && i < start; i = val.indexOf("\r", i+1), start++) {}
|
|
2113
|
-
|
|
2114
|
-
if (localRange.compareEndPoints("EndToEnd", endRange) > -1)
|
|
2115
|
-
return {start: start, end: len};
|
|
2116
|
-
|
|
2117
|
-
var end = -localRange.moveEnd("character", -len);
|
|
2118
|
-
for (var i = val.indexOf("\r"); i > -1 && i < end; i = val.indexOf("\r", i+1), end++) {}
|
|
2119
|
-
return {start: start, end: end};
|
|
2120
|
-
};
|
|
2121
|
-
setSelRange = function(te, start, end) {
|
|
2122
|
-
var range = te.createTextRange();
|
|
2123
|
-
range.collapse(true);
|
|
2124
|
-
var endrange = range.duplicate();
|
|
2125
|
-
var newlines = 0, txt = te.value;
|
|
2126
|
-
for (var pos = txt.indexOf("\n"); pos > -1 && pos < start; pos = txt.indexOf("\n", pos + 1))
|
|
2127
|
-
++newlines;
|
|
2128
|
-
range.move("character", start - newlines);
|
|
2129
|
-
for (; pos > -1 && pos < end; pos = txt.indexOf("\n", pos + 1))
|
|
2130
|
-
++newlines;
|
|
2131
|
-
endrange.move("character", end - newlines);
|
|
2132
|
-
range.setEndPoint("EndToEnd", endrange);
|
|
2133
|
-
range.select();
|
|
2134
|
-
};
|
|
2135
|
-
}
|
|
3108
|
+
var hasSelection = window.getSelection ? function(te) {
|
|
3109
|
+
try { return te.selectionStart != te.selectionEnd; }
|
|
3110
|
+
catch(e) { return false; }
|
|
3111
|
+
} : function(te) {
|
|
3112
|
+
try {var range = te.ownerDocument.selection.createRange();}
|
|
3113
|
+
catch(e) {}
|
|
3114
|
+
if (!range || range.parentElement() != te) return false;
|
|
3115
|
+
return range.compareEndPoints("StartToEnd", range) != 0;
|
|
3116
|
+
};
|
|
2136
3117
|
|
|
2137
3118
|
CodeMirror.defineMode("null", function() {
|
|
2138
3119
|
return {token: function(stream) {stream.skipToEnd();}};
|
|
2139
3120
|
});
|
|
2140
3121
|
CodeMirror.defineMIME("text/plain", "null");
|
|
2141
3122
|
|
|
3123
|
+
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
|
|
3124
|
+
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
|
|
3125
|
+
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
|
|
3126
|
+
46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
|
|
3127
|
+
186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
|
|
3128
|
+
221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
|
|
3129
|
+
63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
|
|
3130
|
+
CodeMirror.keyNames = keyNames;
|
|
3131
|
+
(function() {
|
|
3132
|
+
// Number keys
|
|
3133
|
+
for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
|
|
3134
|
+
// Alphabetic keys
|
|
3135
|
+
for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
|
|
3136
|
+
// Function keys
|
|
3137
|
+
for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
|
|
3138
|
+
})();
|
|
3139
|
+
|
|
3140
|
+
CodeMirror.version = "2.34";
|
|
3141
|
+
|
|
2142
3142
|
return CodeMirror;
|
|
2143
|
-
})()
|
|
2144
|
-
;
|
|
3143
|
+
})();
|