codemirror-rails 3.13 → 3.14

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.
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
+ })();