codemirror-rails 3.13 → 3.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +328 -250
  4. data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +7 -6
  5. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +33 -7
  6. data/vendor/assets/javascripts/codemirror/addons/edit/matchbrackets.js +14 -10
  7. data/vendor/assets/javascripts/codemirror/addons/edit/trailingspace.js +15 -0
  8. data/vendor/assets/javascripts/codemirror/addons/fold/brace-fold.js +70 -17
  9. data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +56 -20
  10. data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +135 -39
  11. data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +324 -571
  12. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +199 -109
  13. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +60 -113
  14. data/vendor/assets/javascripts/codemirror/addons/lint/coffeescript-lint.js +24 -0
  15. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +431 -0
  16. data/vendor/assets/javascripts/codemirror/addons/mode/multiplex.js +7 -1
  17. data/vendor/assets/javascripts/codemirror/addons/search/match-highlighter.js +46 -20
  18. data/vendor/assets/javascripts/codemirror/addons/search/search.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +370 -13
  20. data/vendor/assets/javascripts/codemirror/keymaps/extra.js +43 -0
  21. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +535 -214
  22. data/vendor/assets/javascripts/codemirror/modes/clike.js +56 -0
  23. data/vendor/assets/javascripts/codemirror/modes/javascript.js +19 -14
  24. data/vendor/assets/javascripts/codemirror/modes/markdown.js +2 -2
  25. data/vendor/assets/javascripts/codemirror/modes/ruby.js +67 -16
  26. data/vendor/assets/javascripts/codemirror/modes/smarty.js +167 -110
  27. data/vendor/assets/javascripts/codemirror/modes/sql.js +97 -15
  28. data/vendor/assets/javascripts/codemirror/modes/xml.js +14 -18
  29. data/vendor/assets/stylesheets/codemirror.css +0 -1
  30. data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +82 -0
  31. metadata +7 -2
@@ -0,0 +1,24 @@
1
+ // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js
2
+
3
+ CodeMirror.coffeeValidator = function(text) {
4
+ var found = [];
5
+ var parseError = function(err) {
6
+ var loc = err.lineNumber;
7
+ found.push({from: CodeMirror.Pos(loc-1, 0),
8
+ to: CodeMirror.Pos(loc, 0),
9
+ severity: err.level,
10
+ message: err.message});
11
+ };
12
+ try {
13
+ var res = coffeelint.lint(text);
14
+ for(var i = 0; i < res.length; i++) {
15
+ parseError(res[i]);
16
+ }
17
+ } catch(e) {
18
+ found.push({from: CodeMirror.Pos(e.location.first_line, 0),
19
+ to: CodeMirror.Pos(e.location.last_line, e.location.last_column),
20
+ severity: 'error',
21
+ message: e.message});
22
+ }
23
+ return found;
24
+ };
@@ -0,0 +1,431 @@
1
+ (function() {
2
+ "use strict";
3
+
4
+ var Pos = CodeMirror.Pos;
5
+ var svgNS = "http://www.w3.org/2000/svg";
6
+
7
+ function DiffView(mv, type) {
8
+ this.mv = mv;
9
+ this.type = type;
10
+ this.classes = type == "left"
11
+ ? {chunk: "CodeMirror-diff-l-chunk",
12
+ start: "CodeMirror-diff-l-chunk-start",
13
+ end: "CodeMirror-diff-l-chunk-end",
14
+ insert: "CodeMirror-diff-l-inserted",
15
+ del: "CodeMirror-diff-l-deleted",
16
+ connect: "CodeMirror-diff-l-connect"}
17
+ : {chunk: "CodeMirror-diff-r-chunk",
18
+ start: "CodeMirror-diff-r-chunk-start",
19
+ end: "CodeMirror-diff-r-chunk-end",
20
+ insert: "CodeMirror-diff-r-inserted",
21
+ del: "CodeMirror-diff-r-deleted",
22
+ connect: "CodeMirror-diff-r-connect"};
23
+ }
24
+
25
+ DiffView.prototype = {
26
+ constructor: DiffView,
27
+ init: function(pane, orig, options) {
28
+ this.edit = this.mv.edit;
29
+ this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: true}, copyObj(options)));
30
+
31
+ this.diff = getDiff(orig, options.value);
32
+ this.diffOutOfDate = false;
33
+
34
+ this.forceUpdate = registerUpdate(this);
35
+ setScrollLock(this, true, false);
36
+ registerScroll(this);
37
+ }
38
+ };
39
+
40
+ function registerUpdate(dv) {
41
+ var edit = {from: 0, to: 0, marked: []};
42
+ var orig = {from: 0, to: 0, marked: []};
43
+ var debounceChange;
44
+ function update() {
45
+ if (dv.diffOutOfDate) {
46
+ dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue());
47
+ dv.diffOutOfDate = false;
48
+ }
49
+ updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
50
+ updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
51
+ drawConnectors(dv);
52
+ }
53
+ function set(slow) {
54
+ clearTimeout(debounceChange);
55
+ debounceChange = setTimeout(update, slow == true ? 250 : 100);
56
+ }
57
+ dv.edit.on("change", function() {
58
+ if (!dv.diffOutOfDate) {
59
+ dv.diffOutOfDate = true;
60
+ edit.from = edit.to = orig.from = orig.to = 0;
61
+ }
62
+ set(true);
63
+ });
64
+ dv.edit.on("viewportChange", set);
65
+ dv.orig.on("viewportChange", set);
66
+ update();
67
+ return update;
68
+ }
69
+
70
+ function registerScroll(dv) {
71
+ dv.edit.on("scroll", function() {
72
+ syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
73
+ });
74
+ dv.orig.on("scroll", function() {
75
+ syncScroll(dv, DIFF_DELETE) && drawConnectors(dv);
76
+ });
77
+ }
78
+
79
+ function syncScroll(dv, type) {
80
+ // Change handler will do a refresh after a timeout when diff is out of date
81
+ if (dv.diffOutOfDate) return false;
82
+ if (!dv.lockScroll) return true;
83
+ var editor, other, now = +new Date;
84
+ if (type == DIFF_INSERT) { editor = dv.edit; other = dv.orig; }
85
+ else { editor = dv.orig; other = dv.edit; }
86
+ // Don't take action if the position of this editor was recently set
87
+ // (to prevent feedback loops)
88
+ if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false;
89
+
90
+ var sInfo = editor.getScrollInfo(), halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;
91
+ var mid = editor.lineAtHeight(midY, "local");
92
+ var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
93
+ var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig);
94
+ var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit);
95
+ var ratio = (midY - off.top) / (off.bot - off.top);
96
+ other.scrollTo(null, (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top));
97
+ other.state.scrollSetAt = now;
98
+ other.state.scrollSetBy = dv;
99
+ return true;
100
+ }
101
+
102
+ function getOffsets(editor, around) {
103
+ var bot = around.after;
104
+ if (bot == null) bot = editor.lastLine() + 1;
105
+ return {top: editor.heightAtLine(around.before || 0, "local"),
106
+ bot: editor.heightAtLine(bot, "local")};
107
+ }
108
+
109
+ function setScrollLock(dv, val, action) {
110
+ dv.lockScroll = val;
111
+ if (val && action != false) syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
112
+ dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db&nbsp;&nbsp;\u21da";
113
+ }
114
+
115
+ // Updating the marks for editor content
116
+
117
+ function clearMarks(editor, arr, classes) {
118
+ for (var i = 0; i < arr.length; ++i) {
119
+ var mark = arr[i];
120
+ if (mark instanceof CodeMirror.TextMarker) {
121
+ mark.clear();
122
+ } else {
123
+ editor.removeLineClass(mark, "background", classes.chunk);
124
+ editor.removeLineClass(mark, "background", classes.start);
125
+ editor.removeLineClass(mark, "background", classes.end);
126
+ }
127
+ }
128
+ arr.length = 0;
129
+ }
130
+
131
+ // FIXME maybe add a margin around viewport to prevent too many updates
132
+ function updateMarks(editor, diff, state, type, classes) {
133
+ var vp = editor.getViewport();
134
+ editor.operation(function() {
135
+ if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
136
+ clearMarks(editor, state.marked, classes);
137
+ markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes);
138
+ state.from = vp.from; state.to = vp.to;
139
+ } else {
140
+ if (vp.from < state.from) {
141
+ markChanges(editor, diff, type, state.marked, vp.from, state.from, classes);
142
+ state.from = vp.from;
143
+ }
144
+ if (vp.to > state.to) {
145
+ markChanges(editor, diff, type, state.marked, state.to, vp.to, classes);
146
+ state.to = vp.to;
147
+ }
148
+ }
149
+ });
150
+ }
151
+
152
+ function markChanges(editor, diff, type, marks, from, to, classes) {
153
+ var pos = Pos(0, 0);
154
+ var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1));
155
+ var cls = type == DIFF_DELETE ? classes.del : classes.insert;
156
+ function markChunk(start, end) {
157
+ var bfrom = Math.max(from, start), bto = Math.min(to, end);
158
+ for (var i = bfrom; i < bto; ++i) {
159
+ var line = editor.addLineClass(i, "background", classes.chunk);
160
+ if (i == start) editor.addLineClass(line, "background", classes.start);
161
+ if (i == end - 1) editor.addLineClass(line, "background", classes.end);
162
+ marks.push(line);
163
+ }
164
+ // When the chunk is empty, make sure a horizontal line shows up
165
+ if (start == end && bfrom == end && bto == end) {
166
+ if (bfrom)
167
+ marks.push(editor.addLineClass(bfrom - 1, "background", classes.end));
168
+ else
169
+ marks.push(editor.addLineClass(bfrom, "background", classes.start));
170
+ }
171
+ }
172
+
173
+ var chunkStart = 0;
174
+ for (var i = 0; i < diff.length; ++i) {
175
+ var part = diff[i], tp = part[0], str = part[1];
176
+ if (tp == DIFF_EQUAL) {
177
+ var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1);
178
+ moveOver(pos, str);
179
+ var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0);
180
+ if (cleanTo > cleanFrom) {
181
+ if (i) markChunk(chunkStart, cleanFrom);
182
+ chunkStart = cleanTo;
183
+ }
184
+ } else {
185
+ if (tp == type) {
186
+ var end = moveOver(pos, str, true);
187
+ var a = posMax(top, pos), b = posMin(bot, end);
188
+ if (!posEq(a, b))
189
+ marks.push(editor.markText(a, b, {className: cls}));
190
+ pos = end;
191
+ }
192
+ }
193
+ }
194
+ if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1);
195
+ }
196
+
197
+ // Updating the gap between editor and original
198
+
199
+ function drawConnectors(dv) {
200
+ if (dv.svg) {
201
+ clear(dv.svg);
202
+ var w = dv.gap.offsetWidth;
203
+ attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight);
204
+ }
205
+ clear(dv.copyButtons);
206
+
207
+ var flip = dv.type == "left";
208
+ var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
209
+ var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top;
210
+ iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
211
+ if (topEdit >= vpEdit.to || botEdit < vpEdit.from ||
212
+ topOrig >= vpOrig.to || botOrig < vpOrig.from)
213
+ return;
214
+ var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx;
215
+ if (dv.svg) {
216
+ var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
217
+ if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
218
+ var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
219
+ var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit;
220
+ if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
221
+ var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
222
+ var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
223
+ attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")),
224
+ "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
225
+ "class", dv.classes.connect);
226
+ }
227
+ var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
228
+ "CodeMirror-diff-copy"));
229
+ copy.title = "Revert chunk";
230
+ copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig};
231
+ copy.style.top = top + "px";
232
+ });
233
+ }
234
+
235
+ function copyChunk(dv, chunk) {
236
+ if (dv.diffOutOfDate) return;
237
+ dv.edit.replaceRange(dv.orig.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)),
238
+ Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0));
239
+ }
240
+
241
+ // Merge view, containing 0, 1, or 2 diff views.
242
+
243
+ var MergeView = CodeMirror.MergeView = function(node, options) {
244
+ if (!(this instanceof MergeView)) return new MergeView(node, options);
245
+
246
+ var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
247
+ var hasLeft = origLeft != null, hasRight = origRight != null;
248
+ var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
249
+ var wrap = [], left = this.left = null, right = this.right = null;
250
+
251
+ if (hasLeft) {
252
+ left = this.left = new DiffView(this, "left");
253
+ var leftPane = elt("div", null, "CodeMirror-diff-pane");
254
+ wrap.push(leftPane);
255
+ wrap.push(buildGap(left));
256
+ }
257
+
258
+ var editPane = elt("div", null, "CodeMirror-diff-pane");
259
+ wrap.push(editPane);
260
+
261
+ if (hasRight) {
262
+ right = this.right = new DiffView(this, "right");
263
+ wrap.push(buildGap(right));
264
+ var rightPane = elt("div", null, "CodeMirror-diff-pane");
265
+ wrap.push(rightPane);
266
+ }
267
+
268
+ wrap.push(elt("div", null, null, "height: 0; clear: both;"));
269
+ var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-diff CodeMirror-diff-" + panes + "pane"));
270
+ this.edit = CodeMirror(editPane, copyObj(options));
271
+
272
+ if (left) left.init(leftPane, origLeft, options);
273
+ if (right) right.init(rightPane, origRight, options);
274
+
275
+ var onResize = function() {
276
+ if (left) drawConnectors(left);
277
+ if (right) drawConnectors(right);
278
+ };
279
+ CodeMirror.on(window, "resize", onResize);
280
+ var resizeInterval = setInterval(function() {
281
+ for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {}
282
+ if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); }
283
+ }, 5000);
284
+ };
285
+
286
+ function buildGap(dv) {
287
+ var lock = dv.lockButton = elt("div", null, "CodeMirror-diff-scrolllock");
288
+ lock.title = "Toggle locked scrolling";
289
+ var lockWrap = elt("div", [lock], "CodeMirror-diff-scrolllock-wrap");
290
+ CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); });
291
+ dv.copyButtons = elt("div", null, "CodeMirror-diff-copybuttons-" + dv.type);
292
+ CodeMirror.on(dv.copyButtons, "click", function(e) {
293
+ var node = e.target || e.srcElement;
294
+ if (node.chunk) copyChunk(dv, node.chunk);
295
+ });
296
+ var gapElts = [dv.copyButtons, lockWrap];
297
+ var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
298
+ if (svg && !svg.createSVGRect) svg = null;
299
+ dv.svg = svg;
300
+ if (svg) gapElts.push(svg);
301
+
302
+ return dv.gap = elt("div", gapElts, "CodeMirror-diff-gap");
303
+ }
304
+
305
+ MergeView.prototype = {
306
+ constuctor: MergeView,
307
+ editor: function() { return this.edit; },
308
+ rightOriginal: function() { return this.right && this.right.orig; },
309
+ leftOriginal: function() { return this.left && this.left.orig; }
310
+ };
311
+
312
+ // Operations on diffs
313
+
314
+ var dmp = new diff_match_patch();
315
+ function getDiff(a, b) {
316
+ var diff = dmp.diff_main(a, b);
317
+ dmp.diff_cleanupSemantic(diff);
318
+ // The library sometimes leaves in empty parts, which confuse the algorithm
319
+ for (var i = 0; i < diff.length; ++i) {
320
+ var part = diff[i];
321
+ if (!part[1]) {
322
+ diff.splice(i--, 1);
323
+ } else if (i && diff[i - 1][0] == part[0]) {
324
+ diff.splice(i--, 1);
325
+ diff[i][1] += part[1];
326
+ }
327
+ }
328
+ return diff;
329
+ }
330
+
331
+ function iterateChunks(diff, f) {
332
+ var startEdit = 0, startOrig = 0;
333
+ var edit = Pos(0, 0), orig = Pos(0, 0);
334
+ for (var i = 0; i < diff.length; ++i) {
335
+ var part = diff[i], tp = part[0];
336
+ if (tp == DIFF_EQUAL) {
337
+ var startOff = startOfLineClean(diff, i) ? 0 : 1;
338
+ var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff;
339
+ moveOver(edit, part[1], null, orig);
340
+ var endOff = endOfLineClean(diff, i) ? 1 : 0;
341
+ var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff;
342
+ if (cleanToEdit > cleanFromEdit) {
343
+ if (i) f(startOrig, cleanFromOrig, startEdit, cleanFromEdit);
344
+ startEdit = cleanToEdit; startOrig = cleanToOrig;
345
+ }
346
+ } else {
347
+ moveOver(tp == DIFF_INSERT ? edit : orig, part[1]);
348
+ }
349
+ }
350
+ if (startEdit <= edit.line || startOrig <= orig.line)
351
+ f(startOrig, orig.line + 1, startEdit, edit.line + 1);
352
+ }
353
+
354
+ function endOfLineClean(diff, i) {
355
+ if (i == diff.length - 1) return true;
356
+ var next = diff[i + 1][1];
357
+ if (next.length == 1 || next.charCodeAt(0) != 10) return false;
358
+ if (i == diff.length - 2) return true;
359
+ next = diff[i + 2][1];
360
+ return next.length > 1 && next.charCodeAt(0) == 10;
361
+ }
362
+
363
+ function startOfLineClean(diff, i) {
364
+ if (i == 0) return true;
365
+ var last = diff[i - 1][1];
366
+ if (last.charCodeAt(last.length - 1) != 10) return false;
367
+ if (i == 1) return true;
368
+ last = diff[i - 2][1];
369
+ return last.charCodeAt(last.length - 1) == 10;
370
+ }
371
+
372
+ function chunkBoundariesAround(diff, n, nInEdit) {
373
+ var beforeE, afterE, beforeO, afterO;
374
+ iterateChunks(diff, function(fromOrig, toOrig, fromEdit, toEdit) {
375
+ var fromLocal = nInEdit ? fromEdit : fromOrig;
376
+ var toLocal = nInEdit ? toEdit : toOrig;
377
+ if (afterE == null) {
378
+ if (fromLocal > n) { afterE = fromEdit; afterO = fromOrig; }
379
+ else if (toLocal > n) { afterE = toEdit; afterO = toOrig; }
380
+ }
381
+ if (toLocal <= n) { beforeE = toEdit; beforeO = toOrig; }
382
+ else if (fromLocal <= n) { beforeE = fromEdit; beforeO = fromOrig; }
383
+ });
384
+ return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}};
385
+ }
386
+
387
+ // General utilities
388
+
389
+ function elt(tag, content, className, style) {
390
+ var e = document.createElement(tag);
391
+ if (className) e.className = className;
392
+ if (style) e.style.cssText = style;
393
+ if (typeof content == "string") e.appendChild(document.createTextNode(content));
394
+ else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
395
+ return e;
396
+ }
397
+
398
+ function clear(node) {
399
+ for (var count = node.childNodes.length; count > 0; --count)
400
+ node.removeChild(node.firstChild);
401
+ }
402
+
403
+ function attrs(elt) {
404
+ for (var i = 1; i < arguments.length; i += 2)
405
+ elt.setAttribute(arguments[i], arguments[i+1]);
406
+ }
407
+
408
+ function copyObj(obj, target) {
409
+ if (!target) target = {};
410
+ for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
411
+ return target;
412
+ }
413
+
414
+ function moveOver(pos, str, copy, other) {
415
+ var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0;
416
+ for (;;) {
417
+ var nl = str.indexOf("\n", at);
418
+ if (nl == -1) break;
419
+ ++out.line;
420
+ if (other) ++other.line;
421
+ at = nl + 1;
422
+ }
423
+ out.ch = (at ? 0 : out.ch) + (str.length - at);
424
+ if (other) other.ch = (at ? 0 : other.ch) + (str.length - at);
425
+ return out;
426
+ }
427
+
428
+ function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; }
429
+ function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; }
430
+ function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }
431
+ })();