Showing with 4,166 additions and 2,882 deletions.
  1. +5 −3 CONTRIBUTING.md
  2. +3 −1 README.md
  3. +5 −3 addon/edit/closebrackets.js
  4. +2 −1 addon/edit/closetag.js
  5. +16 −8 addon/edit/matchbrackets.js
  6. +1 −1 addon/fold/brace-fold.js
  7. +7 −5 addon/hint/javascript-hint.js
  8. +17 −17 addon/hint/pig-hint.js
  9. +17 −9 addon/hint/show-hint.js
  10. +59 −59 addon/lint/javascript-lint.js
  11. +36 −22 addon/lint/lint.js
  12. +2 −2 addon/mode/multiplex.js
  13. +2 −2 addon/mode/overlay.js
  14. +1 −1 addon/search/match-highlighter.js
  15. +16 −13 addon/search/searchcursor.js
  16. +1 −1 addon/selection/active-line.js
  17. +11 −0 bin/lint
  18. +2 −0 demo/theme.html
  19. +4 −1 doc/compress.html
  20. +1 −1 doc/internals.html
  21. +310 −254 doc/manual.html
  22. +1 −0 doc/modes.html
  23. +2 −2 doc/oldrelease.html
  24. +4 −0 doc/realworld.html
  25. +17 −2 index.html
  26. +265 −6 keymap/vim.js
  27. +1 −1 lib/codemirror.css
  28. +137 −68 lib/codemirror.js
  29. +6 −6 mode/asterisk/asterisk.js
  30. +14 −14 mode/clike/clike.js
  31. +4 −5 mode/clojure/clojure.js
  32. +1 −1 mode/coffeescript/coffeescript.js
  33. +12 −12 mode/ecl/ecl.js
  34. +1 −1 mode/erlang/erlang.js
  35. +326 −0 mode/gas/gas.js
  36. +57 −0 mode/gas/index.html
  37. +26 −26 mode/haskell/haskell.js
  38. +15 −15 mode/haxe/haxe.js
  39. +6 −6 mode/htmlembedded/htmlembedded.js
  40. +8 −4 mode/javascript/index.html
  41. +53 −23 mode/javascript/javascript.js
  42. +2 −2 mode/jinja2/jinja2.js
  43. +38 −38 mode/less/less.js
  44. +7 −7 mode/lua/lua.js
  45. +39 −39 mode/markdown/markdown.js
  46. +11 −11 mode/markdown/test.js
  47. +1 −0 mode/meta.js
  48. +57 −57 mode/mirc/mirc.js
  49. +22 −22 mode/ntriples/ntriples.js
  50. +1 −1 mode/ocaml/ocaml.js
  51. +791 −791 mode/perl/perl.js
  52. +163 −163 mode/pig/pig.js
  53. +24 −24 mode/python/python.js
  54. +1 −1 mode/q/q.js
  55. +3 −3 mode/rst/rst.js
  56. +2 −2 mode/sass/sass.js
  57. +2 −2 mode/shell/shell.js
  58. +10 −10 mode/sieve/sieve.js
  59. +129 −129 mode/smalltalk/smalltalk.js
  60. +3 −3 mode/smarty/smarty.js
  61. +1 −1 mode/sparql/sparql.js
  62. +22 −22 mode/sql/sql.js
  63. +1 −1 mode/tcl/tcl.js
  64. +345 −345 mode/tiddlywiki/tiddlywiki.js
  65. +297 −298 mode/tiki/tiki.js
  66. +14 −14 mode/turtle/turtle.js
  67. +30 −31 mode/vb/vb.js
  68. +4 −4 mode/vbscript/vbscript.js
  69. +1 −1 mode/xml/xml.js
  70. +55 −55 mode/xquery/xquery.js
  71. +90 −90 mode/yaml/yaml.js
  72. +82 −110 mode/z80/z80.js
  73. +1 −1 package.json
  74. +10 −6 test/lint/lint.js
  75. +1 −1 test/test.js
  76. +379 −0 test/vim_test.js
  77. +1 −1 theme/eclipse.css
  78. +52 −0 theme/midnight.css
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ should be asked on the
test suite under `mode/XXX/test.js`. Feel free to add new test
suites to modes that don't have one yet (be sure to link the new
tests into `test/index.html`).
- Follow the general code style of the rest of the project (see
below). Run `bin/lint` to verify that the linter is happy.
- Make sure all tests pass. Visit `test/index.html` in your browser to
run them.
- Submit a pull request
Expand All @@ -65,6 +67,6 @@ should be asked on the

- 2 spaces per indentation level, no tabs.
- Include semicolons after statements.
- Note that the linter (`test/lint/lint.js`) which is run after each
commit complains about unused variables and functions. Prefix their
names with an underscore to muffle it.
- Note that the linter (`bin/lint`) which is run after each commit
complains about unused variables and functions. Prefix their names
with an underscore to muffle it.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# CodeMirror [![Build Status](https://secure.travis-ci.org/marijnh/CodeMirror.png?branch=master)](http://travis-ci.org/marijnh/CodeMirror)
# CodeMirror
[![Build Status](https://secure.travis-ci.org/marijnh/CodeMirror.png?branch=master)](http://travis-ci.org/marijnh/CodeMirror)
[![NPM version](https://badge.fury.io/js/codemirror.png)](http://badge.fury.io/js/codemirror)

CodeMirror is a JavaScript component that provides a code editor in
the browser. When a mode is available for the language you are coding
Expand Down
8 changes: 5 additions & 3 deletions addon/edit/closebrackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
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)
pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0)
cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
else
return CodeMirror.Pass;
Expand All @@ -27,15 +27,17 @@
for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
if (left != right) closingBrackets.push(right);
function surround(cm) {
var selection = cm.getSelection();
cm.replaceSelection(left + selection + right);
var selection = cm.getSelection();
cm.replaceSelection(left + selection + right);
}
function maybeOverwrite(cm) {
var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1));
if (ahead != right || cm.somethingSelected()) return CodeMirror.Pass;
else cm.execCommand("goCharRight");
}
map["'" + left + "'"] = function(cm) {
if (left == "'" && cm.getTokenAt(cm.getCursor()).type == "comment")
return CodeMirror.Pass;
if (cm.somethingSelected()) return surround(cm);
if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return;
var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1);
Expand Down
3 changes: 2 additions & 1 deletion addon/edit/closetag.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
var lowerTagName = tagName.toLowerCase();
// Don't process the '>' at the end of an end-tag or self-closing tag
if (tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") > -1 ||
if (tok.type == "tag" && state.type == "closeTag" ||
tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1)
return CodeMirror.Pass;

Expand Down
24 changes: 16 additions & 8 deletions addon/edit/matchbrackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
(document.documentMode == null || document.documentMode < 8);

var Pos = CodeMirror.Pos;
// Disable brace matching in long lines, since it'll cause hugely slow updates
var maxLineLen = 1000;

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

var cur = 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;
Expand All @@ -18,10 +18,12 @@
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) && cm.getTokenAt(Pos(lineNo, pos + 1)).type == style) {
if (re.test(ch) && (!checkTokenStyles || cm.getTokenAt(Pos(lineNo, pos + 1)).type == 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 @@ -38,9 +40,11 @@
}

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 found = findMatchingBracket(cm);
if (!found || cm.getLine(found.from.line).length > maxLineLen ||
found.to && cm.getLine(found.to.line).length > maxLineLen)
if (!found || cm.getLine(found.from.line).length > maxHighlightLen ||
found.to && cm.getLine(found.to.line).length > maxHighlightLen)
return;

var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
Expand All @@ -64,9 +68,13 @@
});
}

CodeMirror.defineOption("matchBrackets", false, function(cm, val) {
if (val) cm.on("cursorActivity", doMatchBrackets);
else cm.off("cursorActivity", doMatchBrackets);
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init)
cm.off("cursorActivity", doMatchBrackets);
if (val) {
cm.state._matchBrackets = typeof val == "object" ? val : {};
cm.on("cursorActivity", doMatchBrackets);
}
});

CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
Expand Down
2 changes: 1 addition & 1 deletion addon/fold/brace-fold.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CodeMirror.braceRangeFinder = function(cm, start) {
var line = start.line, lineText = cm.getLine(line);
var at = lineText.length, startChar, tokenType;
for (;;) {
for (; at > 0;) {
var found = lineText.lastIndexOf("{", at);
if (found < start.ch) break;
tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
Expand Down
12 changes: 7 additions & 5 deletions addon/hint/javascript-hint.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
}

function arrayContains(arr, item) {
if (!Array.prototype.indexOf) {
var i = arr.length;
Expand All @@ -21,8 +21,10 @@
function scriptHint(editor, keywords, getToken, options) {
// Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;

// If it's not a 'word-style' token, ignore the token.
if (!/^[\w$_]*$/.test(token.string)) {
if (!/^[\w$_]*$/.test(token.string)) {
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
type: token.string == "." ? "property" : null};
}
Expand All @@ -42,9 +44,9 @@
}
} while (level > 0);
tprop = getToken(editor, Pos(cur.line, tprop.start));
if (tprop.type.indexOf("variable") === 0)
tprop.type = "function";
else return; // no clue
if (tprop.type.indexOf("variable") === 0)
tprop.type = "function";
else return; // no clue
}
if (!context) var context = [];
context.push(tprop);
Expand Down
34 changes: 17 additions & 17 deletions addon/hint/pig-hint.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
}

function arrayContains(arr, item) {
if (!Array.prototype.indexOf) {
var i = arr.length;
Expand All @@ -25,11 +25,11 @@
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
className: token.string == ":" ? "pig-type" : null};
}

if (!context) var context = [];
context.push(tprop);
var completionList = getCompletions(token, context);

var completionList = getCompletions(token, context);
completionList = completionList.sort();
//prevent autocomplete for last word, instead show dropdown with one word
if(completionList.length == 1) {
Expand All @@ -40,24 +40,24 @@
from: CodeMirror.Pos(cur.line, token.start),
to: CodeMirror.Pos(cur.line, token.end)};
}

CodeMirror.pigHint = function(editor) {
return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
};

var pigKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
+ "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
+ "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
+ "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ "NEQ MATCHES TRUE FALSE";
var pigKeywordsU = pigKeywords.split(" ");
var pigKeywordsL = pigKeywords.toLowerCase().split(" ");

var pigTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP";
var pigTypesU = pigTypes.split(" ");
var pigTypesL = pigTypes.toLowerCase().split(" ");
var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "

var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+ "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
+ "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
+ "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
Expand All @@ -66,23 +66,23 @@
+ "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
+ "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
+ "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
+ "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER";
var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" ");
var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" ");
+ "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER";
var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" ");
var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" ");
var pigBuiltinsC = ("BagSize BinStorage Bloom BuildBloom ConstantSize CubeDimensions DoubleAbs "
+ "DoubleAvg DoubleBase DoubleMax DoubleMin DoubleRound DoubleSum FloatAbs FloatAvg FloatMax "
+ "FloatMin FloatRound FloatSum GenericInvoker IntAbs IntAvg IntMax IntMin IntSum "
+ "InvokeForDouble InvokeForFloat InvokeForInt InvokeForLong InvokeForString Invoker "
+ "IsEmpty JsonLoader JsonMetadata JsonStorage LongAbs LongAvg LongMax LongMin LongSum MapSize "
+ "MonitoredUDF Nondeterministic OutputSchema PigStorage PigStreaming StringConcat StringMax "
+ "StringMin StringSize TextLoader TupleSize Utf8StorageConverter").split(" ").join("() ").split(" ");

function getCompletions(token, context) {
var found = [], start = token.string;
function maybeAdd(str) {
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
}

function gatherCompletions(obj) {
if(obj == ":") {
forEach(pigTypesL, maybeAdd);
Expand All @@ -103,11 +103,11 @@
// find in the current environment.
var obj = context.pop(), base;

if (obj.type == "variable")
if (obj.type == "variable")
base = obj.string;
else if(obj.type == "variable-3")
base = ":" + obj.string;

while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
Expand Down
26 changes: 17 additions & 9 deletions addon/hint/show-hint.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ CodeMirror.showHint = function(cm, getHints, options) {
// When there is only one completion, use it directly.
if (!continued && options.completeSingle !== false && completions.length == 1) {
pickCompletion(cm, data, completions[0]);
CodeMirror.signal(data, "close");
return true;
}

Expand All @@ -41,14 +42,15 @@ CodeMirror.showHint = function(cm, getHints, options) {
if (completion.className != null) className = completion.className + " " + className;
elt.className = className;
if (completion.render) completion.render(elt, data, completion);
else elt.appendChild(document.createTextNode(getText(completion)));
else elt.appendChild(document.createTextNode(completion.displayText || getText(completion)));
elt.hintId = i;
}
var pos = cm.cursorCoords(options.alignWithWord !== false ? data.from : null);
var left = pos.left, top = pos.bottom, below = true;
hints.style.left = left + "px";
hints.style.top = top + "px";
document.body.appendChild(hints);
CodeMirror.signal(data, "shown");

// If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
Expand Down Expand Up @@ -85,13 +87,14 @@ CodeMirror.showHint = function(cm, getHints, options) {
hints.scrollTop = node.offsetTop - 3;
else if (node.offsetTop + node.offsetHeight > hints.scrollTop + hints.clientHeight)
hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3;
CodeMirror.signal(data, "select", completions[selectedHint], node);
}

function screenAmount() {
return Math.floor(hints.clientHeight / hints.firstChild.offsetHeight) || 1;
}

var ourMap = {
var ourMap, baseMap = {
Up: function() {changeActive(selectedHint - 1);},
Down: function() {changeActive(selectedHint + 1);},
PageUp: function() {changeActive(selectedHint - screenAmount());},
Expand All @@ -102,11 +105,14 @@ CodeMirror.showHint = function(cm, getHints, options) {
Tab: pick,
Esc: close
};
if (options.customKeys) for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) {
var val = options.customKeys[key];
if (/^(Up|Down|Enter|Esc)$/.test(key)) val = ourMap[val];
ourMap[key] = val;
}
if (options.customKeys) {
ourMap = {};
for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) {
var val = options.customKeys[key];
if (baseMap.hasOwnProperty(val)) val = baseMap[val];
ourMap[key] = val;
}
} else ourMap = baseMap;

cm.addKeyMap(ourMap);
cm.on("cursorActivity", cursorActivity);
Expand Down Expand Up @@ -138,7 +144,7 @@ CodeMirror.showHint = function(cm, getHints, options) {
});

var done = false, once;
function close() {
function close(willContinue) {
if (done) return;
done = true;
clearTimeout(once);
Expand All @@ -148,6 +154,7 @@ CodeMirror.showHint = function(cm, getHints, options) {
cm.off("blur", onBlur);
cm.off("focus", onFocus);
cm.off("scroll", onScroll);
if (willContinue !== true) CodeMirror.signal(data, "close");
}
function pick() {
pickCompletion(cm, data, completions[selectedHint]);
Expand All @@ -163,8 +170,9 @@ CodeMirror.showHint = function(cm, getHints, options) {
(pos.ch && closeOn.test(line.charAt(pos.ch - 1))))
close();
else
once = setTimeout(function(){close(); continued = true; startHinting();}, 70);
once = setTimeout(function(){close(true); continued = true; startHinting();}, 70);
}
CodeMirror.signal(data, "select", completions[0], hints.firstChild);
return true;
}

Expand Down
Loading