408 changes: 337 additions & 71 deletions keymap/vim.js

Large diffs are not rendered by default.

44 changes: 43 additions & 1 deletion lib/codemirror.css
Original file line number Diff line number Diff line change
@@ -1,17 +1,54 @@
.CodeMirror {
line-height: 1em;
font-family: monospace;

/* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
position: relative;
/* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
overflow: hidden;
}

.CodeMirror-scroll {
overflow: auto;
overflow-x: auto;
overflow-y: hidden;
height: 300px;
/* This is needed to prevent an IE[67] bug where the scrolled content
is visible outside of the scrolling box. */
position: relative;
outline: none;
}

/* Vertical scrollbar */
.CodeMirror-scrollbar {
float: right;
overflow-x: hidden;
overflow-y: scroll;

/* This corrects for the 1px gap introduced to the left of the scrollbar
by the rule for .CodeMirror-scrollbar-inner. */
margin-left: -1px;
}
.CodeMirror-scrollbar-inner {
/* This needs to have a nonzero width in order for the scrollbar to appear
in Firefox and IE9. */
width: 1px;
}
.CodeMirror-scrollbar.cm-sb-overlap {
/* Ensure that the scrollbar appears in Lion, and that it overlaps the content
rather than sitting to the right of it. */
position: absolute;
z-index: 1;
float: none;
right: 0;
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-nonoverlap {
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-ie7 {
min-width: 18px;
}

.CodeMirror-gutter {
position: absolute; left: 0; top: 0;
z-index: 10;
Expand All @@ -29,6 +66,11 @@
.CodeMirror-lines {
padding: .4em;
white-space: pre;
cursor: text;
}
.CodeMirror-lines * {
/* Necessary for throw-scrolling to decelerate properly on Safari. */
pointer-events: none;
}

.CodeMirror pre {
Expand Down
339 changes: 222 additions & 117 deletions lib/codemirror.js

Large diffs are not rendered by default.

15 changes: 10 additions & 5 deletions lib/util/foldcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// released under the MIT license (../../LICENSE) like the rest of CodeMirror
CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
var nameChar = nameStartChar + "\-\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");

var lineText = cm.getLine(line);
Expand Down Expand Up @@ -110,10 +110,15 @@ CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
};

CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
var lineText = cm.getLine(line);
var startChar = lineText.lastIndexOf("{");
if (startChar < 0 || lineText.lastIndexOf("}") > startChar) return;
var tokenType = cm.getTokenAt({line: line, ch: startChar}).className;
var lineText = cm.getLine(line), at = lineText.length, startChar, tokenType;
for (;;) {
var found = lineText.lastIndexOf("{", at);
if (found < 0) break;
tokenType = cm.getTokenAt({line: line, ch: found}).className;
if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
at = found - 1;
}
if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
var count = 1, lastLine = cm.lineCount(), end;
outer: for (var i = line + 1; i < lastLine; ++i) {
var text = cm.getLine(i), pos = 0;
Expand Down
9 changes: 6 additions & 3 deletions lib/util/formatting.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ CodeMirror.modeExtensions["css"] = {
commentStart: "/*",
commentEnd: "*/",
wordWrapChars: [";", "\\{", "\\}"],
autoFormatLineBreaks: function (text) {
autoFormatLineBreaks: function (text, startPos, endPos) {
text = text.substring(startPos, endPos);
return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
}
};
Expand Down Expand Up @@ -125,7 +126,8 @@ CodeMirror.modeExtensions["javascript"] = {
return nonBreakableBlocks;
},

autoFormatLineBreaks: function (text) {
autoFormatLineBreaks: function (text, startPos, endPos) {
text = text.substring(startPos, endPos);
var curPos = 0;
var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
var nonBreakableBlocks = this.getNonBreakableBlocks(text);
Expand Down Expand Up @@ -158,7 +160,8 @@ CodeMirror.modeExtensions["xml"] = {
commentEnd: "-->",
wordWrapChars: [">"],

autoFormatLineBreaks: function (text) {
autoFormatLineBreaks: function (text, startPos, endPos) {
text = text.substring(startPos, endPos);
var lines = text.split("\n");
var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
var reOpenBrackets = new RegExp("<", "g");
Expand Down
72 changes: 72 additions & 0 deletions lib/util/multiplex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
CodeMirror.multiplexingMode = function(outer /*, others */) {
// Others should be {open, close, mode [, delimStyle]} objects
var others = Array.prototype.slice.call(arguments, 1);
var n_others = others.length;

return {
startState: function() {
return {
outer: CodeMirror.startState(outer),
innerActive: null,
inner: null
};
},

copyState: function(state) {
return {
outer: CodeMirror.copyState(outer, state.outer),
innerActive: state.innerActive,
inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
};
},

token: function(stream, state) {
if (!state.innerActive) {
for (var i = 0; i < n_others; ++i) {
var other = others[i];
if (stream.match(other.open)) {
state.innerActive = other;
state.inner = CodeMirror.startState(other.mode);
return other.delimStyle;
}
}
var outerToken = outer.token(stream, state.outer);
var cur = stream.current();
for (var i = 0; i < n_others; ++i) {
var other = others[i], found = cur.indexOf(other.open);
if (found > -1) {
stream.backUp(cur.length - found);
cur = cur.slice(0, found);
}
}
return outerToken;
} else {
var curInner = state.innerActive;
if (stream.match(curInner.close)) {
state.innerActive = state.inner = null;
return curInner.delimStyle;
}
var innerToken = curInner.mode.token(stream, state.inner);
var cur = stream.current(), found = cur.indexOf(curInner.close);
if (found > -1) stream.backUp(cur.length - found);
return innerToken;
}
},

indent: function(state, textAfter) {
var mode = state.innerActive || outer;
if (!mode.indent) return CodeMirror.Pass;
return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
},

compareStates: function(a, b) {
if (a.innerActive != b.innerActive) return false;
var mode = a.innerActive || outer;
if (!mode.compareStates) return CodeMirror.Pass;
return mode.compareStates(a.innerActive ? a.inner : a.outer,
b.innerActive ? b.inner : b.outer);
},

electricChars: outer.electricChars
};
};
3 changes: 2 additions & 1 deletion lib/util/overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
// overlay wins, unless the combine argument was true, in which case
// the styles are combined.

CodeMirror.overlayParser = function(base, overlay, combine) {
// overlayParser is the old, deprecated name
CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, combine) {
return {
startState: function() {
return {
Expand Down
123 changes: 123 additions & 0 deletions lib/util/pig-hint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
(function () {
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;
while (i--) {
if (arr[i] === item) {
return true;
}
}
return false;
}
return arr.indexOf(item) != -1;
}

function scriptHint(editor, keywords, getToken) {
// Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
// If it's not a 'word-style' token, ignore the token.

if (!/^[\w$_]*$/.test(token.string)) {
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);

completionList = getCompletions(token, context);
completionList = completionList.sort();
//prevent autocomplete for last word, instead show dropdown with one word
if(completionList.length == 1) {
completionList.push(" ");
}

return {list: completionList,
from: {line: cur.line, ch: token.start},
to: {line: cur.line, ch: token.end}};
}

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

function toTitleCase(str) {
return str.replace(/(?:^|\s)\w/g, function(match) {
return match.toUpperCase();
});
}

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 "
+ "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 "
+ "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 "
+ "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
+ "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
+ "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(" ");
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);
}
else {
forEach(pigBuiltinsU, maybeAdd);
forEach(pigBuiltinsL, maybeAdd);
forEach(pigBuiltinsC, maybeAdd);
forEach(pigTypesU, maybeAdd);
forEach(pigTypesL, maybeAdd);
forEach(pigKeywordsU, maybeAdd);
forEach(pigKeywordsL, maybeAdd);
}
}

if (context) {
// If this is a property, see if it belongs to some object we can
// find in the current environment.
var obj = context.pop(), base;

if (obj.className == "pig-word")
base = obj.string;
else if(obj.className == "pig-type")
base = ":" + obj.string;

while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
}
return found;
}
})();
22 changes: 13 additions & 9 deletions lib/util/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
function getSearchState(cm) {
return cm._searchState || (cm._searchState = new SearchState());
}
function getSearchCursor(cm, query, pos) {
// Heuristic: if the query string is all lowercase, do a case insensitive search.
return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
}
function dialog(cm, text, shortText, f) {
if (cm.openDialog) cm.openDialog(text, f);
else f(prompt(shortText, ""));
Expand All @@ -23,8 +27,8 @@
else if (confirm(shortText)) fs[0]();
}
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/$/);
return isRE ? new RegExp(isRE[1]) : query;
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i") : query;
}
var queryDialog =
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
Expand All @@ -36,7 +40,7 @@
if (!query || state.query) return;
state.query = parseQuery(query);
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
for (var cursor = cm.getSearchCursor(query); cursor.findNext();)
for (var cursor = getSearchCursor(cm, query); cursor.findNext();)
state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
}
state.posFrom = state.posTo = cm.getCursor();
Expand All @@ -46,9 +50,9 @@
}
function findNext(cm, rev) {cm.operation(function() {
var state = getSearchState(cm);
var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo);
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
if (!cursor.find(rev)) {
cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
cursor = getSearchCursor(cm, state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
if (!cursor.find(rev)) return;
}
cm.setSelection(cursor.from(), cursor.to());
Expand All @@ -73,7 +77,7 @@
dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
if (all) {
cm.compoundChange(function() { cm.operation(function() {
for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") {
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
Expand All @@ -82,13 +86,13 @@
})});
} else {
clearSearch(cm);
var cursor = cm.getSearchCursor(query, cm.getCursor());
var cursor = getSearchCursor(cm, query, cm.getCursor());
function advance() {
var start = cursor.from(), match;
if (!(match = cursor.findNext())) {
cursor = cm.getSearchCursor(query);
cursor = getSearchCursor(cm, query);
if (!(match = cursor.findNext()) ||
(cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
}
cm.setSelection(cursor.from(), cursor.to());
confirmDialog(cm, doReplaceConfirm, "Replace?",
Expand Down
37 changes: 37 additions & 0 deletions mode/clike/clike.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,41 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
}
}
});
CodeMirror.defineMIME("text/x-scala", {
name: "clike",
keywords: words(

/* scala */
"abstract case catch class def do else extends false final finally for forSome if " +
"implicit import lazy match new null object override package private protected return " +
"sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
"<% >: # @ " +

/* package scala */
"assert assume require print println printf readLine readBoolean readByte readShort " +
"readChar readInt readLong readFloat readDouble " +

"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
"Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +

/* package java.lang */
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"


),
blockKeywords: words("catch class do else finally for forSome if match switch try while"),
atoms: words("true false null"),
hooks: {
"@": function(stream, state) {
stream.eatWhile(/[\w\$_]/);
return "meta";
}
}
});
}());
765 changes: 765 additions & 0 deletions mode/clike/scala.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion mode/ecl/ecl.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,4 @@ CodeMirror.defineMode("ecl", function(config) {
};
});

CodeMirror.defineMIME("text/x-ecl");
CodeMirror.defineMIME("text/x-ecl", "ecl");
40 changes: 38 additions & 2 deletions mode/gfm/gfm.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ CodeMirror.defineMode("gfm", function(config, parserConfig) {
function handleText(stream, mdState) {
var match;
if (stream.match(/^\w+:\/\/\S+/)) {
return 'linkhref';
return 'link';
}
if (stream.match(/^[^\[*\\<>` _][^\[*\\<>` ]*[^\[*\\<>` _]/)) {
return mdMode.getType(mdState);
Expand Down Expand Up @@ -102,7 +102,43 @@ CodeMirror.defineMode("gfm", function(config, parserConfig) {
},

token: function(stream, state) {
return state.token(stream, state);
/* Parse GFM double bracket links */
if ((ch = stream.peek()) != undefined && ch == '[') {
stream.next(); // Advance the stream

/* Only handle double bracket links */
if ((ch = stream.peek()) == undefined || ch != '[') {
stream.backUp(1);
return state.token(stream, state);
}

while ((ch = stream.next()) != undefined && ch != ']') {}

if (ch == ']' && (ch = stream.next()) != undefined && ch == ']')
return 'link';

/* If we did not find the second ']' */
stream.backUp(1);
}

/* Match GFM latex formulas, as well as latex formulas within '$' */
if (stream.match(/^\$[^\$]+\$/)) {
return "string";
}

if (stream.match(/^\\\((.*?)\\\)/)) {
return "string";
}

if (stream.match(/^\$\$[^\$]+\$\$/)) {
return "string";
}

if (stream.match(/^\\\[(.*?)\\\]/)) {
return "string";
}

return state.token(stream, state);
}
}
}, "markdown");
2 changes: 1 addition & 1 deletion mode/less/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="less.js"></script>
<style>.CodeMirror {background: #f8f8f8; border: 1px solid #ddd;} .CodeMirror-scroll {height: 400px}</style>
<style>.CodeMirror {background: #f8f8f8; border: 1px solid #ddd; font-size:12px} .CodeMirror-scroll {height: 400px}</style>
<link rel="stylesheet" href="../../doc/docs.css">
<link rel="stylesheet" href="../../theme/lesser-dark.css">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
Expand Down
11 changes: 3 additions & 8 deletions mode/ruby/ruby.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ CodeMirror.defineMode("ruby", function(config, parserConfig) {
return "comment";
}
if (stream.eatSpace()) return null;
var ch = stream.next();
var ch = stream.next(), m;
if (ch == "`" || ch == "'" || ch == '"' ||
(ch == "/" && !stream.eol() && stream.peek() != " ")) {
return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
Expand All @@ -46,13 +46,8 @@ CodeMirror.defineMode("ruby", function(config, parserConfig) {
} else if (ch == "#") {
stream.skipToEnd();
return "comment";
} else if (ch == "<" && stream.eat("<")) {
stream.eat("-");
stream.eat(/[\'\"\`]/);
var match = stream.match(/^\w+/);
stream.eat(/[\'\"\`]/);
if (match) return chain(readHereDoc(match[0]), stream, state);
return null;
} else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) {
return chain(readHereDoc(m[1]), stream, state);
} else if (ch == "0") {
if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/);
else if (stream.eat("b")) stream.eatWhile(/[01]/);
Expand Down
81 changes: 56 additions & 25 deletions mode/scheme/scheme.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,28 @@ CodeMirror.defineMode("scheme", function (config, mode) {
state.indentStack = state.indentStack.prev;
}

/**
* Scheme numbers are complicated unfortunately.
* Checks if we're looking at a number, which might be possibly a fraction.
* Also checks that it is not part of a longer identifier. Returns true/false accordingly.
*/
function isNumber(ch, stream){
if (!stream.eatWhile(/[0-9]/)) {
if (stream.eat(/\//)) stream.eatWhile(/[0-9]/);
if (stream.eol() || !(/[a-zA-Z\-\_\/]/.test(stream.peek()))) return true;
stream.backUp(stream.current().length - 1); // undo all the eating
var binaryMatcher = new RegExp(/^(?:[-+]i|[-+][01]+#*(?:\/[01]+#*)?i|[-+]?[01]+#*(?:\/[01]+#*)?@[-+]?[01]+#*(?:\/[01]+#*)?|[-+]?[01]+#*(?:\/[01]+#*)?[-+](?:[01]+#*(?:\/[01]+#*)?)?i|[-+]?[01]+#*(?:\/[01]+#*)?)(?=[()\s;"]|$)/i);
var octalMatcher = new RegExp(/^(?:[-+]i|[-+][0-7]+#*(?:\/[0-7]+#*)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?@[-+]?[0-7]+#*(?:\/[0-7]+#*)?|[-+]?[0-7]+#*(?:\/[0-7]+#*)?[-+](?:[0-7]+#*(?:\/[0-7]+#*)?)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?)(?=[()\s;"]|$)/i);
var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\da-f]+#*(?:\/[\da-f]+#*)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?@[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?[-+](?:[\da-f]+#*(?:\/[\da-f]+#*)?)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?)(?=[()\s;"]|$)/i);
var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)i|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)@[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)?i|(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*))(?=[()\s;"]|$)/i);

function isBinaryNumber (stream) {
return stream.match(binaryMatcher);
}

function isOctalNumber (stream) {
return stream.match(octalMatcher);
}

function isDecimalNumber (stream, backup) {
if (backup === true) {
stream.backUp(1);
}
return false;
return stream.match(decimalMatcher);
}

function isHexNumber (stream) {
return stream.match(hexMatcher);
}

return {
Expand Down Expand Up @@ -111,29 +121,50 @@ CodeMirror.defineMode("scheme", function (config, mode) {
} else if (ch == "'") {
returnType = ATOM;
} else if (ch == '#') {
if (stream.eat("|")) { // Multi-line comment
if (stream.eat("|")) { // Multi-line comment
state.mode = "comment"; // toggle to comment mode
returnType = COMMENT;
} else if (stream.eat(/[tf]/)) { // #t/#f (atom)
} else if (stream.eat(/[tf]/i)) { // #t/#f (atom)
returnType = ATOM;
} else if (stream.eat(';')) { // S-Expr comment
} else if (stream.eat(';')) { // S-Expr comment
state.mode = "s-expr-comment";
returnType = COMMENT;
} else {
var numTest = null, hasExactness = false, hasRadix = true;
if (stream.eat(/[ei]/i)) {
hasExactness = true;
} else {
stream.backUp(1); // must be radix specifier
}
if (stream.match(/^#b/i)) {
numTest = isBinaryNumber;
} else if (stream.match(/^#o/i)) {
numTest = isOctalNumber;
} else if (stream.match(/^#x/i)) {
numTest = isHexNumber;
} else if (stream.match(/^#d/i)) {
numTest = isDecimalNumber;
} else if (stream.match(/^[-+0-9.]/, false)) {
hasRadix = false;
numTest = isDecimalNumber;
// re-consume the intial # if all matches failed
} else if (!hasExactness) {
stream.eat('#');
}
if (numTest != null) {
if (hasRadix && !hasExactness) {
// consume optional exactness after radix
stream.match(/^#[ei]/i);
}
if (numTest(stream))
returnType = NUMBER;
}
}

} else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal
returnType = NUMBER;
} else if (ch == ";") { // comment
stream.skipToEnd(); // rest of the line is a comment
returnType = COMMENT;
} else if (ch == "-"){

if(!isNaN(parseInt(stream.peek()))){
stream.eatWhile(/[\/0-9]/);
returnType = NUMBER;
}else{
returnType = null;
}
} else if (isNumber(ch,stream)){
returnType = NUMBER;
} else if (ch == "(" || ch == "[") {
var keyWord = ''; var indentTemp = stream.column();
/**
Expand Down
10 changes: 6 additions & 4 deletions mode/stex/stex.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,12 @@ CodeMirror.defineMode("stex", function(cmCfg, modeCfg)
if (source.match(/^\\[a-zA-Z@]+/)) {
var cmdName = source.current();
cmdName = cmdName.substr(1, cmdName.length-1);
var plug = plugins[cmdName];
if (typeof(plug) == 'undefined') {
plug = plugins["DEFAULT"];
}
var plug;
if (plugins.hasOwnProperty(cmdName)) {
plug = plugins[cmdName];
} else {
plug = plugins["DEFAULT"];
}
plug = new plug();
pushCommand(state, plug);
setState(state, beginParams);
Expand Down
12 changes: 12 additions & 0 deletions mode/stex/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,18 @@ <h2>Spacing control</h2>

</script>

<h2>New Commands</h2>

Should be able to define a new command that happens to be a method on Array
(e.g. <tt>pop</tt>):
<script language="javascript">
MT.test('\\newcommand{\\pop}',
'tag', '\\newcommand',
'bracket', '{',
'tag', '\\pop',
'bracket', '}');
</script>

<h2>Summary</h2>
<script language="javascript">
MT.printSummary();
Expand Down
29 changes: 29 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "CodeMirror",
"version":"2.30.0",
"main": "codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [
{
"type": "MIT",
"url": "http://codemirror.net/LICENSE"
}
],
"directories": {
"lib": "./lib"
},
"bugs": "http://github.com/marijnh/CodeMirror2/issues",
"keywords": ["JavaScript", "CodeMirror", "Editor"],
"homepage": "http://codemirror.net",
"maintainers":[ {
"name": "Marijn Haverbeke",
"email": "marijnh@gmail.com",
"web": "http://codemirror.net"
}],
"repositories": [
{
"type": "git",
"url": "https://github.com/marijnh/CodeMirror2.git"
}
]
}
7 changes: 7 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ testCM("bookmark", function(cm) {
});
});

testCM("bug577", function(cm) {
cm.setValue("a\nb");
cm.clearHistory();
cm.setValue("fooooo");
cm.undo();
});

// Scaffolding

function htmlEscape(str) {
Expand Down
3 changes: 1 addition & 2 deletions theme/ambiance.css
5 changes: 2 additions & 3 deletions theme/lesser-dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
http://lesscss.org/ dark theme
Ported to CodeMirror by Peter Kroon
*/
.CodeMirror{
line-height: 15px;
.cm-s-lesser-dark {
line-height: 1.3em;
}
.cm-s-lesser-dark {
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Monaco', Courier, monospace !important;
font-size:12px;
}

.cm-s-lesser-dark { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }
Expand Down
2 changes: 1 addition & 1 deletion theme/night.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* Loosely based on the Midnight Textmate theme */

.cm-s-night { background: #0a001f; color: #f8f8f8; }
.cm-s-night div.CodeMirror-selected { background: #a8f !important; }
.cm-s-night div.CodeMirror-selected { background: #447 !important; }
.cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
.cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; }
.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
Expand Down
27 changes: 27 additions & 0 deletions theme/vibrant-ink.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* Taken from the popular Visual Studio Vibrant Ink Schema */

.cm-s-vibrant-ink { background: black; color: white; }
.cm-s-vibrant-ink .CodeMirror-selected { background: #35493c !important; }

.cm-s-vibrant-ink .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; }
.cm-s-vibrant-ink .CodeMirror-gutter-text { color: #d0d0d0; }
.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white !important; }

.cm-s-vibrant-ink .cm-keyword { color: #CC7832; }
.cm-s-vibrant-ink .cm-atom { color: #FC0; }
.cm-s-vibrant-ink .cm-number { color: #FFEE98; }
.cm-s-vibrant-ink .cm-def { color: #8DA6CE; }
.cm-s-vibrant-ink span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #FFC66D }
.cm-s-vibrant-ink span.cm-variable-3, .cm-s-cobalt span.cm-def { color: #FFC66D }
.cm-s-vibrant-ink .cm-operator { color: #888; }
.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }
.cm-s-vibrant-ink .cm-string { color: #A5C25C }
.cm-s-vibrant-ink .cm-string-2 { color: red }
.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }
.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-header { color: #FF6400; }
.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }
.cm-s-vibrant-ink .cm-link { color: blue; }