Showing with 2,567 additions and 554 deletions.
  1. +144 −0 addon/comment/comment.js
  2. +4 −4 addon/display/placeholder.js
  3. +2 −2 addon/edit/closebrackets.js
  4. +9 −3 addon/fold/brace-fold.js
  5. +3 −3 addon/lint/lint.css
  6. +13 −13 addon/lint/lint.js
  7. +5 −1 addon/runmode/runmode.js
  8. +13 −1 addon/runmode/runmode.node.js
  9. +4 −4 addon/search/match-highlighter.js
  10. +1 −1 addon/search/search.js
  11. +15 −5 addon/search/searchcursor.js
  12. +6 −6 addon/selection/active-line.js
  13. +89 −15 addon/selection/mark-selection.js
  14. +4 −3 bin/compress
  15. +61 −0 bin/source-highlight
  16. +3 −0 doc/compress.html
  17. +133 −23 doc/manual.html
  18. +2 −0 doc/modes.html
  19. +28 −0 doc/oldrelease.html
  20. +11 −0 doc/realworld.html
  21. +30 −47 index.html
  22. +451 −187 keymap/vim.js
  23. +7 −4 lib/codemirror.css
  24. +167 −115 lib/codemirror.js
  25. +6 −3 mode/clike/clike.js
  26. +3 −1 mode/clojure/clojure.js
  27. +240 −0 mode/cobol/cobol.js
  28. +195 −0 mode/cobol/index.html
  29. +2 −1 mode/coffeescript/coffeescript.js
  30. +5 −1 mode/commonlisp/commonlisp.js
  31. +63 −24 mode/css/css.js
  32. +3 −2 mode/erlang/erlang.js
  33. +5 −1 mode/gas/gas.js
  34. +4 −1 mode/go/go.js
  35. +153 −0 mode/haml/haml.js
  36. +67 −0 mode/haml/index.html
  37. +94 −0 mode/haml/test.js
  38. +5 −1 mode/haskell/haskell.js
  39. +3 −1 mode/javascript/index.html
  40. +5 −1 mode/javascript/javascript.js
  41. +0 −8 mode/less/less.js
  42. +5 −1 mode/lua/lua.js
  43. +2 −2 mode/markdown/markdown.js
  44. +2 −0 mode/meta.js
  45. +4 −1 mode/ocaml/ocaml.js
  46. +3 −0 mode/php/php.js
  47. +2 −1 mode/python/python.js
  48. +2 −1 mode/ruby/ruby.js
  49. +4 −1 mode/rust/rust.js
  50. +8 −27 mode/sass/sass.js
  51. +3 −1 mode/scheme/scheme.js
  52. +6 −4 mode/smalltalk/smalltalk.js
  53. +0 −1 mode/sql/index.html
  54. +3 −4 mode/sql/sql.js
  55. +1 −1 mode/stex/stex.js
  56. +3 −0 mode/stex/test.js
  57. +2 −0 mode/xml/xml.js
  58. +3 −1 mode/yaml/yaml.js
  59. +1 −1 package.json
  60. +46 −0 test/comment_test.js
  61. +2 −1 test/driver.js
  62. +10 −2 test/index.html
  63. +4 −1 test/test.js
  64. +392 −20 test/vim_test.js
  65. +1 −1 theme/rubyblue.css
144 changes: 144 additions & 0 deletions addon/comment/comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
(function() {
"use strict";

var noOptions = {};
var nonWS = /[^\s\u00a0]/;
var Pos = CodeMirror.Pos;

function firstNonWS(str) {
var found = str.search(nonWS);
return found == -1 ? 0 : found;
}

CodeMirror.commands.toggleComment = function(cm) {
var from = cm.getCursor("start"), to = cm.getCursor("end");
cm.uncomment(from, to) || cm.lineComment(from, to);
};

CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode;
var commentString = options.lineComment || mode.lineComment;
if (!commentString) {
if (options.blockCommentStart || mode.blockCommentStart) {
options.fullLines = true;
self.blockComment(from, to, options);
}
return;
}
var firstLine = self.getLine(from.line);
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;

self.operation(function() {
if (options.indent) {
var baseString = firstLine.slice(0, firstNonWS(firstLine));
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i), cut = baseString.length;
if (!blankLines && !nonWS.test(line)) continue;
if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
}
} else {
for (var i = from.line; i < end; ++i) {
if (blankLines || nonWS.test(self.getLine(i)))
self.replaceRange(commentString + pad, Pos(i, 0));
}
}
});
});

CodeMirror.defineExtension("blockComment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode;
var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) {
if ((options.lineComment || mode.lineComment) && options.fullLines != false)
self.lineComment(from, to, options);
return;
}

var end = Math.min(to.line, self.lastLine());
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;

var pad = options.padding == null ? " " : options.padding;
if (from.line > end) return;

self.operation(function() {
if (options.fullLines != false) {
var lastLineHasText = nonWS.test(self.getLine(end));
self.replaceRange(pad + endString, Pos(end));
self.replaceRange(startString + pad, Pos(from.line, 0));
var lead = options.blockCommentLead || mode.blockCommentLead;
if (lead != null) for (var i = from.line + 1; i <= end; ++i)
if (i != end || lastLineHasText)
self.replaceRange(lead + pad, Pos(i, 0));
} else {
self.replaceRange(endString, to);
self.replaceRange(startString, from);
}
});
});

CodeMirror.defineExtension("uncomment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode;
var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end);

// Try finding line comments
var lineString = options.lineComment || mode.lineComment, lines = [];
var pad = options.padding == null ? " " : options.padding;
lineComment: for(;;) {
if (!lineString) break;
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;
lines.push(line);
}
self.operation(function() {
for (var i = start; i <= end; ++i) {
var line = lines[i - start];
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
if (pos < 0) continue;
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
}
});
return true;
}

// Try block comments
var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) return false;
var lead = options.blockCommentLead || mode.blockCommentLead;
var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);
var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);
if (close == -1 && start != end) {
endLine = self.getLine(--end);
close = endLine.lastIndexOf(endString);
}
if (open == -1 || close == -1) return false;

self.operation(function() {
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
Pos(end, close + endString.length));
var openEnd = open + startString.length;
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
self.replaceRange("", Pos(start, open), Pos(start, openEnd));
if (lead) for (var i = start + 1; i <= end; ++i) {
var line = self.getLine(i), found = line.indexOf(lead);
if (found == -1 || nonWS.test(line.slice(0, found))) continue;
var foundEnd = found + lead.length;
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
}
});
return true;
});
})();
8 changes: 4 additions & 4 deletions addon/display/placeholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
});

function clearPlaceholder(cm) {
if (cm._placeholder) {
cm._placeholder.parentNode.removeChild(cm._placeholder);
cm._placeholder = null;
if (cm.state.placeholder) {
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
cm.state.placeholder = null;
}
}
function setPlaceholder(cm) {
clearPlaceholder(cm);
var elt = cm._placeholder = document.createElement("pre");
var elt = cm.state.placeholder = document.createElement("pre");
elt.style.cssText = "height: 0; overflow: visible";
elt.className = "CodeMirror-placeholder";
elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
Expand Down
4 changes: 2 additions & 2 deletions addon/edit/closebrackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
return CodeMirror.Pass;
}
};
var closingBrackets = [];
var closingBrackets = "";
for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
if (left != right) closingBrackets.push(right);
if (left != right) closingBrackets += right;
function surround(cm) {
var selection = cm.getSelection();
cm.replaceSelection(left + selection + right);
Expand Down
12 changes: 9 additions & 3 deletions addon/fold/brace-fold.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@ CodeMirror.braceRangeFinder = function(cm, start) {
var at = lineText.length, startChar, tokenType;
for (; at > 0;) {
var found = lineText.lastIndexOf("{", at);
if (found < start.ch) break;
var startToken = '{', endToken = '}';
if (found < start.ch) {
found = lineText.lastIndexOf("[", at);
if (found < start.ch) break;
startToken = '['; endToken = ']';
}

tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
at = found - 1;
}
if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
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;
for (;;) {
var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
Expand Down
6 changes: 3 additions & 3 deletions addon/lint/lint.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@
-ms-transition: opacity .4s;
}

.CodeMirror-lint-span-error, .CodeMirror-lint-span-warning {
.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
background-position: left bottom;
background-repeat: repeat-x;
}

.CodeMirror-lint-span-error {
.CodeMirror-lint-mark-error {
background-image:
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
;
}

.CodeMirror-lint-span-warning {
.CodeMirror-lint-mark-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
}

Expand Down
26 changes: 13 additions & 13 deletions addon/lint/lint.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ CodeMirror.validate = (function() {
}

function clearMarks(cm) {
var state = cm._lintState;
var state = cm.state.lint;
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
for (var i = 0; i < state.marked.length; ++i)
state.marked[i].clear();
Expand Down Expand Up @@ -105,16 +105,16 @@ CodeMirror.validate = (function() {
}

function startLinting(cm) {
var state = cm._lintState, options = state.options;
if (options.async)
options.getAnnotations(cm, updateLinting, options);
else
updateLinting(cm, options.getAnnotations(cm.getValue()));
var state = cm.state.lint, options = state.options;
if (options.async)
options.getAnnotations(cm, updateLinting, options);
else
updateLinting(cm, options.getAnnotations(cm.getValue()));
}

function updateLinting(cm, annotationsNotSorted) {
clearMarks(cm);
var state = cm._lintState, options = state.options;
var state = cm.state.lint, options = state.options;

var annotations = groupByLine(annotationsNotSorted);

Expand All @@ -135,7 +135,7 @@ CodeMirror.validate = (function() {
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));

if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
className: "CodeMirror-lint-span-" + severity,
className: "CodeMirror-lint-mark-" + severity,
__annotation: ann
}));
}
Expand All @@ -148,7 +148,7 @@ CodeMirror.validate = (function() {
}

function onChange(cm) {
var state = cm._lintState;
var state = cm.state.lint;
clearTimeout(state.timeout);
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
}
Expand All @@ -164,7 +164,7 @@ CodeMirror.validate = (function() {
var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0];

function onMouseOver(cm, e) {
if (!/\bCodeMirror-lint-span-/.test((e.target || e.srcElement).className)) return;
if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return;
for (var i = 0; i < nearby.length; i += 2) {
var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i],
top: e.clientY + nearby[i + 1]}));
Expand All @@ -179,14 +179,14 @@ CodeMirror.validate = (function() {
if (old && old != CodeMirror.Init) {
clearMarks(cm);
cm.off("change", onChange);
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm._lintState.onMouseOver);
delete cm._lintState;
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
delete cm.state.lint;
}

if (val) {
var gutters = cm.getOption("gutters"), hasLintGutter = false;
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter);
var state = cm.state.lint = new LintState(cm, parseOptions(val), hasLintGutter);
cm.on("change", onChange);
if (state.options.tooltips != false)
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
Expand Down
6 changes: 5 additions & 1 deletion addon/runmode/runmode.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
CodeMirror.runMode = function(string, modespec, callback, options) {
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
var ie = /MSIE \d/.test(navigator.userAgent);
var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);

if (callback.nodeType == 1) {
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
var node = callback, col = 0;
node.innerHTML = "";
callback = function(text, style) {
if (text == "\n") {
node.appendChild(document.createElement("br"));
// Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
// Emitting a carriage return makes everything ok.
node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
col = 0;
return;
}
Expand Down
14 changes: 13 additions & 1 deletion addon/runmode/runmode.node.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,20 @@ exports.startState = function(mode, a1, a2) {
};

var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
exports.defineMode = function(name, mode) { modes[name] = mode; };
exports.defineMode = function(name, mode) {
if (arguments.length > 2) {
mode.dependencies = [];
for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
}
modes[name] = mode;
};
exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };

exports.defineMode("null", function() {
return {token: function(stream) {stream.skipToEnd();}};
});
exports.defineMIME("text/plain", "null");

exports.getMode = function(options, spec) {
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
spec = mimeModes[spec];
Expand Down
8 changes: 4 additions & 4 deletions addon/search/match-highlighter.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
cm._matchHighlightState = new State(val);
cm.state.matchHighlighter = new State(val);
cm.on("cursorActivity", highlightMatches);
} else if (!val && prev) {
var over = cm._matchHighlightState.overlay;
var over = cm.state.matchHighlighter.overlay;
if (over) cm.removeOverlay(over);
cm._matchHighlightState = null;
cm.state.matchHighlighter = null;
cm.off("cursorActivity", highlightMatches);
}
});

function highlightMatches(cm) {
cm.operation(function() {
var state = cm._matchHighlightState;
var state = cm.state.matchHighlighter;
if (state.overlay) {
cm.removeOverlay(state.overlay);
state.overlay = null;
Expand Down
2 changes: 1 addition & 1 deletion addon/search/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
this.overlay = null;
}
function getSearchState(cm) {
return cm._searchState || (cm._searchState = new SearchState());
return cm.state.search || (cm.state.search = new SearchState());
}
function getSearchCursor(cm, query, pos) {
// Heuristic: if the query string is all lowercase, do a case insensitive search.
Expand Down
Loading