Showing with 4,490 additions and 1,827 deletions.
  1. +7 −6 addon/comment/comment.js
  2. +33 −7 addon/edit/closebrackets.js
  3. +14 −10 addon/edit/matchbrackets.js
  4. +15 −0 addon/edit/trailingspace.js
  5. +70 −17 addon/fold/brace-fold.js
  6. +56 −20 addon/fold/foldcode.js
  7. +135 −39 addon/fold/xml-fold.js
  8. +324 −571 addon/hint/html-hint.js
  9. +199 −109 addon/hint/show-hint.js
  10. +60 −113 addon/hint/xml-hint.js
  11. +24 −0 addon/lint/coffeescript-lint.js
  12. +50 −0 addon/merge/dep/diff_match_patch.js
  13. +82 −0 addon/merge/merge.css
  14. +431 −0 addon/merge/merge.js
  15. +7 −1 addon/mode/multiplex.js
  16. +30 −0 addon/mode/multiplex_test.js
  17. +46 −20 addon/search/match-highlighter.js
  18. +1 −1 addon/search/search.js
  19. +9 −5 bin/lint
  20. +16 −0 bower.json
  21. +6 −0 demo/emacs.html
  22. +9 −9 demo/folding.html
  23. +14 −62 demo/html5complete.html
  24. +63 −0 demo/merge.html
  25. +6 −0 demo/multiplex.html
  26. +1 −0 demo/theme.html
  27. +39 −0 demo/trailingspace.html
  28. +75 −50 demo/xmlcomplete.html
  29. +2 −0 doc/compress.html
  30. +334 −88 doc/manual.html
  31. +14 −0 doc/oldrelease.html
  32. +2 −0 doc/realworld.html
  33. +35 −24 index.html
  34. +370 −13 keymap/emacs.js
  35. +43 −0 keymap/extra.js
  36. +535 −214 keymap/vim.js
  37. +0 −1 lib/codemirror.css
  38. +327 −249 lib/codemirror.js
  39. +56 −0 mode/clike/clike.js
  40. +19 −14 mode/javascript/javascript.js
  41. +2 −2 mode/markdown/markdown.js
  42. +6 −0 mode/markdown/test.js
  43. +67 −16 mode/ruby/ruby.js
  44. +44 −1 mode/smarty/index.html
  45. +167 −110 mode/smarty/smarty.js
  46. +3 −2 mode/sql/index.html
  47. +97 −15 mode/sql/sql.js
  48. +14 −18 mode/xml/xml.js
  49. +3 −5 package.json
  50. +5 −0 test/comment_test.js
  51. +1 −1 test/driver.js
  52. +135 −0 test/emacs_test.js
  53. +5 −0 test/index.html
  54. +1 −1 test/lint/lint.js
  55. +3 −3 test/mode_test.js
  56. +1 −0 test/run.js
  57. +87 −8 test/test.js
  58. +290 −2 test/vim_test.js
13 changes: 7 additions & 6 deletions addon/comment/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
if (firstLine == null) return;
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
var pad = options.padding == null ? " " : options.padding;
var blankLines = options.commentBlankLines;
var blankLines = options.commentBlankLines || from.line == to.line;

self.operation(function() {
if (options.indent) {
Expand Down Expand Up @@ -90,14 +90,14 @@

// Try finding line comments
var lineString = options.lineComment || mode.lineComment, lines = [];
var pad = options.padding == null ? " " : options.padding;
lineComment: for(;;) {
if (!lineString) break;
var pad = options.padding == null ? " " : options.padding, didSomething;
lineComment: {
if (!lineString) break lineComment;
for (var i = start; i <= end; ++i) {
var line = self.getLine(i);
var found = line.indexOf(lineString);
if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
if (i != start && nonWS.test(line.slice(0, found))) break lineComment;
if (i != start && found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
lines.push(line);
}
self.operation(function() {
Expand All @@ -106,10 +106,11 @@
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
if (pos < 0) continue;
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
didSomething = true;
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
}
});
return true;
if (didSomething) return true;
}

// Try block comments
Expand Down
40 changes: 33 additions & 7 deletions addon/edit/closebrackets.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
(function() {
var DEFAULT_BRACKETS = "()[]{}''\"\"";
var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
var SPACE_CHAR_REGEX = /\s/;

CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
var wasOn = old && old != CodeMirror.Init;
if (val && !wasOn)
cm.addKeyMap(buildKeymap(typeof val == "string" ? val : DEFAULT_BRACKETS));
else if (!val && wasOn)
if (old != CodeMirror.Init && old)
cm.removeKeyMap("autoCloseBrackets");
if (!val) return;
var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
if (typeof val == "string") pairs = val;
else if (typeof val == "object") {
if (val.pairs != null) pairs = val.pairs;
if (val.explode != null) explode = val.explode;
}
var map = buildKeymap(pairs);
if (explode) map.Enter = buildExplodeHandler(explode);
cm.addKeyMap(map);
});

function charsAround(cm, pos) {
var str = cm.getRange(CodeMirror.Pos(pos.line, pos.ch - 1),
CodeMirror.Pos(pos.line, pos.ch + 1));
return str.length == 2 ? str : null;
}

function buildKeymap(pairs) {
var map = {
name : "autoCloseBrackets",
Backspace: function(cm) {
if (cm.somethingSelected()) return CodeMirror.Pass;
var cur = cm.getCursor(), line = cm.getLine(cur.line);
if (cur.ch && cur.ch < line.length &&
pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0)
var cur = cm.getCursor(), around = charsAround(cm, cur);
if (around && pairs.indexOf(around) % 2 == 0)
cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
else
return CodeMirror.Pass;
Expand Down Expand Up @@ -51,4 +64,17 @@
})(pairs.charAt(i), pairs.charAt(i + 1));
return map;
}

function buildExplodeHandler(pairs) {
return function(cm) {
var cur = cm.getCursor(), around = charsAround(cm, cur);
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
cm.operation(function() {
var newPos = CodeMirror.Pos(cur.line + 1, 0);
cm.replaceSelection("\n\n", {anchor: newPos, head: newPos}, "+input");
cm.indentLine(cur.line + 1, null, true);
cm.indentLine(cur.line + 2, null, true);
});
};
}
})();
24 changes: 14 additions & 10 deletions addon/edit/matchbrackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,26 @@
var Pos = CodeMirror.Pos;

var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
function findMatchingBracket(cm) {
var maxScanLen = cm.state._matchBrackets.maxScanLineLength || 10000;
function findMatchingBracket(cm, where, strict) {
var state = cm.state.matchBrackets;
var maxScanLen = (state && state.maxScanLineLength) || 10000;

var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
var cur = where || cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
if (!match) return null;
var forward = match.charAt(1) == ">", d = forward ? 1 : -1;
var style = cm.getTokenAt(Pos(cur.line, pos + 1)).type;
if (strict && forward != (pos == cur.ch)) return null;
var style = cm.getTokenTypeAt(Pos(cur.line, pos + 1));

var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
function scan(line, lineNo, start) {
if (!line.text) return;
var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1;
if (line.text.length > maxScanLen) return null;
var checkTokenStyles = line.text.length < 1000;
if (start != null) pos = start + d;
for (; pos != end; pos += d) {
var ch = line.text.charAt(pos);
if (re.test(ch) && (!checkTokenStyles || cm.getTokenAt(Pos(lineNo, pos + 1)).type == style)) {
if (re.test(ch) && cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style) {
var match = matching[ch];
if (match.charAt(1) == ">" == forward) stack.push(ch);
else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
Expand All @@ -36,12 +37,13 @@
else found = scan(cm.getLineHandle(i), i);
if (found) break;
}
return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos), match: found && found.match};
return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos),
match: found && found.match, forward: forward};
}

function matchBrackets(cm, autoclear) {
// Disable brace matching in long lines, since it'll cause hugely slow updates
var maxHighlightLen = cm.state._matchBrackets.maxHighlightLineLength || 1000;
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
var found = findMatchingBracket(cm);
if (!found || cm.getLine(found.from.line).length > maxHighlightLen ||
found.to && cm.getLine(found.to.line).length > maxHighlightLen)
Expand Down Expand Up @@ -72,11 +74,13 @@
if (old && old != CodeMirror.Init)
cm.off("cursorActivity", doMatchBrackets);
if (val) {
cm.state._matchBrackets = typeof val == "object" ? val : {};
cm.state.matchBrackets = typeof val == "object" ? val : {};
cm.on("cursorActivity", doMatchBrackets);
}
});

CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
CodeMirror.defineExtension("findMatchingBracket", function(){return findMatchingBracket(this);});
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict){
return findMatchingBracket(this, pos, strict);
});
})();
15 changes: 15 additions & 0 deletions addon/edit/trailingspace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
if (prev == CodeMirror.Init) prev = false;
if (prev && !val)
cm.removeOverlay("trailingspace");
else if (!prev && val)
cm.addOverlay({
token: function(stream) {
for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
if (i > stream.pos) { stream.pos = i; return null; }
stream.pos = l;
return "trailingspace";
},
name: "trailingspace"
});
});
87 changes: 70 additions & 17 deletions addon/fold/brace-fold.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
CodeMirror.braceRangeFinder = function(cm, start) {
var line = start.line, lineText = cm.getLine(line);
var at = lineText.length, startChar, tokenType;
for (; at > 0;) {
var found = lineText.lastIndexOf("{", at);
var startToken = '{', endToken = '}';
if (found < start.ch) {
found = lineText.lastIndexOf("[", at);
if (found < start.ch) break;
startToken = '['; endToken = ']';
var startCh, tokenType;

function findOpening(openCh) {
for (var at = start.ch, pass = 0;;) {
var found = lineText.lastIndexOf(openCh, at - 1);
if (found == -1) {
if (pass == 1) break;
pass = 1;
at = lineText.length;
continue;
}
if (pass == 1 && found < start.ch) break;
tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
if (!/^(comment|string)/.test(tokenType)) return found + 1;
at = found - 1;
}
}

tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
at = found - 1;
var startToken = "{", endToken = "}", startCh = findOpening("{");
if (startCh == null) {
startToken = "[", endToken = "]";
startCh = findOpening("[");
}
if (startChar == null || lineText.lastIndexOf(startToken) > startChar) return;
var count = 1, lastLine = cm.lineCount(), end, endCh;
outer: for (var i = line + 1; i < lastLine; ++i) {
var text = cm.getLine(i), pos = 0;

if (startCh == null) return;
var count = 1, lastLine = cm.lastLine(), end, endCh;
outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) {
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
Expand All @@ -31,7 +41,50 @@ CodeMirror.braceRangeFinder = function(cm, start) {
++pos;
}
}
if (end == null || end == line + 1) return;
return {from: CodeMirror.Pos(line, startChar + 1),
if (end == null || line == end && endCh == startCh) return;
return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)};
};

CodeMirror.importRangeFinder = function(cm, start) {
function hasImport(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type != "keyword" || start.string != "import") return null;
// Now find closing semicolon, return its position
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
var text = cm.getLine(i), semi = text.indexOf(";");
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
}
}

var start = start.line, has = hasImport(start), prev;
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
return null;
for (var end = has.end;;) {
var next = hasImport(end.line + 1);
if (next == null) break;
end = next.end;
}
return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
};

CodeMirror.includeRangeFinder = function(cm, start) {
function hasInclude(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
}

var start = start.line, has = hasInclude(start);
if (has == null || hasInclude(start - 1) != null) return null;
for (var end = start;;) {
var next = hasInclude(end + 1);
if (next == null) break;
++end;
}
return {from: CodeMirror.Pos(start, has + 1),
to: cm.clipPos(CodeMirror.Pos(end))};
};
76 changes: 56 additions & 20 deletions addon/fold/foldcode.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,68 @@
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
if (widget == null) widget = "\u2194";
if (typeof widget == "string") {
var text = document.createTextNode(widget);
widget = document.createElement("span");
widget.appendChild(text);
widget.className = "CodeMirror-foldmarker";
}
(function() {
"use strict";

return function(cm, pos) {
function doFold(cm, pos, options) {
var finder = options.call ? options : (options && options.rangeFinder);
if (!finder) return;
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
var range = rangeFinder(cm, pos);
if (!range) return;

var present = cm.findMarksAt(range.from), cleared = 0;
for (var i = 0; i < present.length; ++i) {
if (present[i].__isFold) {
++cleared;
present[i].clear();
var minSize = options && options.minFoldSize || 0;

function getRange(allowFolded) {
var range = finder(cm, pos);
if (!range || range.to.line - range.from.line < minSize) return null;
var marks = cm.findMarksAt(range.from);
for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold) {
if (!allowFolded) return null;
range.cleared = true;
marks[i].clear();
}
}
return range;
}

var range = getRange(true);
if (options && options.scanUp) while (!range && pos.line > cm.firstLine()) {
pos = CodeMirror.Pos(pos.line - 1, 0);
range = getRange(false);
}
if (cleared) return;
if (!range || range.cleared) return;

var myWidget = widget.cloneNode(true);
var myWidget = makeWidget(options);
CodeMirror.on(myWidget, "mousedown", function() {myRange.clear();});
var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget,
clearOnEnter: true,
__isFold: true
});
}

function makeWidget(options) {
var widget = (options && options.widget) || "\u2194";
if (typeof widget == "string") {
var text = document.createTextNode(widget);
widget = document.createElement("span");
widget.appendChild(text);
widget.className = "CodeMirror-foldmarker";
}
return widget;
}

// Clumsy backwards-compatible interface
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
};

// New-style interface
CodeMirror.defineExtension("foldCode", function(pos, options) { doFold(this, pos, options); });

CodeMirror.combineRangeFinders = function() {
var funcs = Array.prototype.slice.call(arguments, 0);
return function(cm, start) {
for (var i = 0; i < funcs.length; ++i) {
var found = funcs[i](cm, start);
if (found) return found;
}
};
};
};
})();
Loading