12 changes: 12 additions & 0 deletions mode/http/http.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("http", function() {
function failFirstLine(stream, state) {
stream.skipToEnd();
Expand Down Expand Up @@ -96,3 +106,5 @@ CodeMirror.defineMode("http", function() {
});

CodeMirror.defineMIME("message/http", "http");

});
4 changes: 2 additions & 2 deletions mode/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h2>Language modes</h2>
option.</p>

<div style="-webkit-columns: 100px 2; -moz-columns: 100px 2; columns: 100px 2;">
<ul>
<ul style="margin-top: 0">
<li><a href="apl/index.html">APL</a></li>
<li><a href="asterisk/index.html">Asterisk dialplan</a></li>
<li><a href="clike/index.html">C, C++, C#</a></li>
Expand Down Expand Up @@ -81,7 +81,7 @@ <h2>Language modes</h2>
<li><a href="python/index.html">Python</a></li>
<li><a href="q/index.html">Q</a></li>
<li><a href="r/index.html">R</a></li>
<li>RPM <a href="rpm/spec/index.html">spec</a> and <a href="rpm/changes/index.html">changelog</a></li>
<li><a href="rpm/index.html">RPM</a></li>
<li><a href="rst/index.html">reStructuredText</a></li>
<li><a href="ruby/index.html">Ruby</a></li>
<li><a href="rust/index.html">Rust</a></li>
Expand Down
12 changes: 12 additions & 0 deletions mode/jade/jade.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("jade", function () {
var symbol_regex1 = /^(?:~|!|%|\^|\*|\+|=|\\|:|;|,|\/|\?|&|<|>|\|)/;
var open_paren_regex = /^(\(|\[)/;
Expand Down Expand Up @@ -88,3 +98,5 @@ CodeMirror.defineMode("jade", function () {
});

CodeMirror.defineMIME('text/x-jade', 'jade');

});
17 changes: 15 additions & 2 deletions mode/javascript/javascript.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
// TODO actually recognize syntax of TypeScript constructs

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var statementIndent = parserConfig.statementIndent;
Expand Down Expand Up @@ -301,11 +311,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
poplex.lex = true;

function expect(wanted) {
return function(type) {
function exp(type) {
if (type == wanted) return cont();
else if (wanted == ";") return pass();
else return cont(arguments.callee);
else return cont(exp);
};
return exp;
}

function statement(type, value) {
Expand Down Expand Up @@ -637,3 +648,5 @@ CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });

});
67 changes: 39 additions & 28 deletions mode/jinja2/jinja2.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
CodeMirror.defineMode("jinja2", function() {
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("jinja2", function() {
var keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif",
"extends", "filter", "endfilter", "firstof", "for",
"endfor", "if", "endif", "ifchanged", "endifchanged",
Expand All @@ -15,38 +25,39 @@ CodeMirror.defineMode("jinja2", function() {
keywords = new RegExp("^((" + keywords.join(")|(") + "))\\b");

function tokenBase (stream, state) {
var ch = stream.next();
if (ch == "{") {
if (ch = stream.eat(/\{|%|#/)) {
stream.eat("-");
state.tokenize = inTag(ch);
return "tag";
}
var ch = stream.next();
if (ch == "{") {
if (ch = stream.eat(/\{|%|#/)) {
stream.eat("-");
state.tokenize = inTag(ch);
return "tag";
}
}
}
function inTag (close) {
if (close == "{") {
close = "}";
if (close == "{") {
close = "}";
}
return function (stream, state) {
var ch = stream.next();
if ((ch == close || (ch == "-" && stream.eat(close)))
&& stream.eat("}")) {
state.tokenize = tokenBase;
return "tag";
}
return function (stream, state) {
var ch = stream.next();
if ((ch == close || (ch == "-" && stream.eat(close)))
&& stream.eat("}")) {
state.tokenize = tokenBase;
return "tag";
}
if (stream.match(keywords)) {
return "keyword";
}
return close == "#" ? "comment" : "string";
};
if (stream.match(keywords)) {
return "keyword";
}
return close == "#" ? "comment" : "string";
};
}
return {
startState: function () {
return {tokenize: tokenBase};
},
token: function (stream, state) {
return state.tokenize(stream, state);
}
startState: function () {
return {tokenize: tokenBase};
},
token: function (stream, state) {
return state.tokenize(stream, state);
}
};
});
});
12 changes: 12 additions & 0 deletions mode/julia/julia.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("julia", function(_conf, parserConf) {
var ERRORCLASS = 'error';

Expand Down Expand Up @@ -284,3 +294,5 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {


CodeMirror.defineMIME("text/x-julia", "julia");

});
753 changes: 0 additions & 753 deletions mode/less/index.html

This file was deleted.

347 changes: 0 additions & 347 deletions mode/less/less.js

This file was deleted.

13 changes: 13 additions & 0 deletions mode/livescript/livescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@
* Link to the project's GitHub page:
* https://github.com/duralog/CodeMirror
*/

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

(function() {
CodeMirror.defineMode('livescript', function(){
var tokenBase, external;
Expand Down Expand Up @@ -265,3 +276,5 @@
})();

CodeMirror.defineMIME('text/x-livescript', 'livescript');

});
12 changes: 12 additions & 0 deletions mode/lua/lua.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
// CodeMirror 1 mode.
// highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("lua", function(config, parserConfig) {
var indentUnit = config.indentUnit;

Expand Down Expand Up @@ -142,3 +152,5 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
});

CodeMirror.defineMIME("text/x-lua", "lua");

});
12 changes: 12 additions & 0 deletions mode/markdown/markdown.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror", require("../xml/xml")));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../xml/xml"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

var htmlFound = CodeMirror.modes.hasOwnProperty("xml");
Expand Down Expand Up @@ -746,3 +756,5 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}, "xml");

CodeMirror.defineMIME("text/x-markdown", "markdown");

});
15 changes: 13 additions & 2 deletions mode/meta.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.modeInfo = [
{name: 'APL', mime: 'text/apl', mode: 'apl'},
{name: 'Asterisk', mime: 'text/x-asterisk', mode: 'asterisk'},
Expand Down Expand Up @@ -40,7 +50,7 @@ CodeMirror.modeInfo = [
{name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'},
{name: 'Jinja2', mime: null, mode: 'jinja2'},
{name: 'Julia', mime: 'text/x-julia', mode: 'julia'},
{name: 'LESS', mime: 'text/x-less', mode: 'less'},
{name: 'LESS', mime: 'text/x-less', mode: 'css'},
{name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'},
{name: 'Lua', mime: 'text/x-lua', mode: 'lua'},
{name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'},
Expand Down Expand Up @@ -88,8 +98,9 @@ CodeMirror.modeInfo = [
{name: 'Velocity', mime: 'text/velocity', mode: 'velocity'},
{name: 'Verilog', mime: 'text/x-verilog', mode: 'verilog'},
{name: 'XML', mime: 'application/xml', mode: 'xml'},
{name: 'HTML', mime: 'text/html', mode: 'xml'},
{name: 'XQuery', mime: 'application/xquery', mode: 'xquery'},
{name: 'YAML', mime: 'text/x-yaml', mode: 'yaml'},
{name: 'Z80', mime: 'text/x-z80', mode: 'z80'}
];

});
13 changes: 13 additions & 0 deletions mode/mirc/mirc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
//mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMIME("text/mirc", "mirc");
CodeMirror.defineMode("mirc", function() {
function parseWords(str) {
Expand Down Expand Up @@ -175,3 +186,5 @@ CodeMirror.defineMode("mirc", function() {
}
};
});

});
13 changes: 12 additions & 1 deletion mode/mllike/mllike.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
CodeMirror.defineMode('mllike', function(_config, parserConfig) {
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode('mllike', function(_config, parserConfig) {
var words = {
'let': 'keyword',
'rec': 'keyword',
Expand Down Expand Up @@ -189,3 +198,5 @@ CodeMirror.defineMIME('text/x-fsharp', {
},
slashComments: true
});

});
12 changes: 12 additions & 0 deletions mode/nginx/nginx.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("nginx", function(config) {

function words(str) {
Expand Down Expand Up @@ -161,3 +171,5 @@ CodeMirror.defineMode("nginx", function(config) {
});

CodeMirror.defineMIME("text/nginx", "text/x-nginx-conf");

});
13 changes: 13 additions & 0 deletions mode/ntriples/ntriples.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@
-> ERROR
}
*/

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("ntriples", function() {

var Location = {
Expand Down Expand Up @@ -168,3 +179,5 @@ CodeMirror.defineMode("ntriples", function() {
});

CodeMirror.defineMIME("text/n-triples", "ntriples");

});
12 changes: 12 additions & 0 deletions mode/octave/octave.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("octave", function() {
function wordRegexp(words) {
return new RegExp("^((" + words.join(")|(") + "))\\b");
Expand Down Expand Up @@ -118,3 +128,5 @@ CodeMirror.defineMode("octave", function() {
});

CodeMirror.defineMIME("text/x-octave", "octave");

});
12 changes: 12 additions & 0 deletions mode/pascal/pascal.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("pascal", function() {
function words(str) {
var obj = {}, words = str.split(" ");
Expand Down Expand Up @@ -92,3 +102,5 @@ CodeMirror.defineMode("pascal", function() {
});

CodeMirror.defineMIME("text/x-pascal", "pascal");

});
12 changes: 12 additions & 0 deletions mode/pegjs/pegjs.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../javascript/javascript"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../javascript/javascript"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("pegjs", function (config) {
var jsMode = CodeMirror.getMode(config, "javascript");

Expand Down Expand Up @@ -97,3 +107,5 @@ CodeMirror.defineMode("pegjs", function (config) {
}
};
}, "javascript");

});
157 changes: 84 additions & 73 deletions mode/perl/perl.js

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions mode/php/php.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
(function() {
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../clike/clike"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../clike/clike"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

function keywords(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
Expand Down Expand Up @@ -128,4 +137,4 @@
CodeMirror.defineMIME("application/x-httpd-php", "php");
CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true});
CodeMirror.defineMIME("text/x-php", phpConfig);
})();
});
12 changes: 12 additions & 0 deletions mode/pig/pig.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
* @link https://github.com/prasanthj/pig-codemirror-2
* This implementation is adapted from PL/SQL mode in CodeMirror 2.
*/
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("pig", function(_config, parserConfig) {
var keywords = parserConfig.keywords,
builtins = parserConfig.builtins,
Expand Down Expand Up @@ -171,3 +181,5 @@ CodeMirror.defineMode("pig", function(_config, parserConfig) {

CodeMirror.registerHelper("hintWords", "pig", (pBuiltins + pTypes + pKeywords).split(" "));
}());

});
12 changes: 12 additions & 0 deletions mode/properties/properties.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("properties", function() {
return {
token: function(stream, state) {
Expand Down Expand Up @@ -61,3 +71,5 @@ CodeMirror.defineMode("properties", function() {

CodeMirror.defineMIME("text/x-properties", "properties");
CodeMirror.defineMIME("text/x-ini", "properties");

});
13 changes: 13 additions & 0 deletions mode/puppet/puppet.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("puppet", function () {
// Stores the words from the define method
var words = {};
Expand Down Expand Up @@ -201,4 +211,7 @@ CodeMirror.defineMode("puppet", function () {
}
};
});

CodeMirror.defineMIME("text/x-puppet", "puppet");

});
32 changes: 21 additions & 11 deletions mode/python/python.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";


CodeMirror.defineMode("python", function(conf, parserConf) {
var ERRORCLASS = 'error';

Expand Down Expand Up @@ -365,14 +376,13 @@ CodeMirror.defineMode("python", function(conf, parserConf) {

CodeMirror.defineMIME("text/x-python", "python");

(function() {
"use strict";
var words = function(str){return str.split(' ');};

CodeMirror.defineMIME("text/x-cython", {
name: "python",
extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+
"extern gil include nogil property public"+
"readonly struct union DEF IF ELIF ELSE")
});
})();
var words = function(str){return str.split(' ');};

CodeMirror.defineMIME("text/x-cython", {
name: "python",
extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+
"extern gil include nogil property public"+
"readonly struct union DEF IF ELIF ELSE")
});

});
12 changes: 12 additions & 0 deletions mode/q/q.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("q",function(config){
var indentUnit=config.indentUnit,
curPunc,
Expand Down Expand Up @@ -122,3 +132,5 @@ CodeMirror.defineMode("q",function(config){
};
});
CodeMirror.defineMIME("text/x-q","q");

});
12 changes: 12 additions & 0 deletions mode/r/r.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("r", function(config) {
function wordObj(str) {
var words = str.split(" "), res = {};
Expand Down Expand Up @@ -143,3 +153,5 @@ CodeMirror.defineMode("r", function(config) {
});

CodeMirror.defineMIME("text/x-rsrc", "r");

});
19 changes: 0 additions & 19 deletions mode/rpm/changes/changes.js

This file was deleted.

67 changes: 51 additions & 16 deletions mode/rpm/spec/index.html → mode/rpm/index.html
Original file line number Diff line number Diff line change
@@ -1,34 +1,70 @@
<!doctype html>

<title>CodeMirror: RPM spec mode</title>
<title>CodeMirror: RPM changes mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">

<link rel="stylesheet" href="../../../lib/codemirror.css">
<script src="../../../lib/codemirror.js"></script>
<script src="spec.js"></script>
<link rel="stylesheet" href="spec.css">
<link rel="stylesheet" href="../../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="rpm.js"></script>
<link rel="stylesheet" href="../../doc/docs.css">
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>

<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../../doc/logo.png"></a>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>

<ul>
<li><a href="../../../index.html">Home</a>
<li><a href="../../../doc/manual.html">Manual</a>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
</ul>
<ul>
<li><a href="../../index.html">Language modes</a>
<li><a class=active href="#">RPM spec</a>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">RPM</a>
</ul>
</div>

<article>
<h2>RPM changes mode</h2>

<div><textarea id="code" name="code">
-------------------------------------------------------------------
Tue Oct 18 13:58:40 UTC 2011 - misterx@example.com

- Update to r60.3
- Fixes bug in the reflect package
* disallow Interface method on Value obtained via unexported name

-------------------------------------------------------------------
Thu Oct 6 08:14:24 UTC 2011 - misterx@example.com

- Update to r60.2
- Fixes memory leak in certain map types

-------------------------------------------------------------------
Wed Oct 5 14:34:10 UTC 2011 - misterx@example.com

- Tweaks for gdb debugging
- go.spec changes:
- move %go_arch definition to %prep section
- pass correct location of go specific gdb pretty printer and
functions to cpp as HOST_EXTRA_CFLAGS macro
- install go gdb functions & printer
- gdb-printer.patch
- patch linker (src/cmd/ld/dwarf.c) to emit correct location of go
gdb functions and pretty printer
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "rpm-changes"},
lineNumbers: true,
indentUnit: 4
});
</script>

<h2>RPM spec mode</h2>

<div><textarea id="code" name="code">
<div><textarea id="code2" name="code2">
#
# spec file for package minidlna
#
Expand Down Expand Up @@ -102,13 +138,12 @@ <h2>RPM spec mode</h2>

%changelog</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "spec"},
var editor = CodeMirror.fromTextArea(document.getElementById("code2"), {
mode: {name: "rpm-spec"},
lineNumbers: true,
indentUnit: 4
});
</script>

<p><strong>MIME types defined:</strong> <code>text/x-rpm-spec</code>.</p>

<p><strong>MIME types defined:</strong> <code>text/x-rpm-spec</code>, <code>text/x-rpm-changes</code>.</p>
</article>
36 changes: 34 additions & 2 deletions mode/rpm/spec/spec.js → mode/rpm/rpm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("rpm-changes", function() {
var headerSeperator = /^-+$/;
var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?\d{1,2} \d{2}:\d{2}(:\d{2})? [A-Z]{3,4} \d{4} - /;
var simpleEmail = /^[\w+.-]+@[\w.-]+/;

return {
token: function(stream) {
if (stream.sol()) {
if (stream.match(headerSeperator)) { return 'tag'; }
if (stream.match(headerLine)) { return 'tag'; }
}
if (stream.match(simpleEmail)) { return 'string'; }
stream.next();
return null;
}
};
});

CodeMirror.defineMIME("text/x-rpm-changes", "rpm-changes");

// Quick and dirty spec file highlighting

CodeMirror.defineMode("spec", function() {
CodeMirror.defineMode("rpm-spec", function() {
var arch = /^(i386|i586|i686|x86_64|ppc64|ppc|ia64|s390x|s390|sparc64|sparcv9|sparc|noarch|alphaev6|alpha|hppa|mipsel)/;

var preamble = /^(Name|Version|Release|License|Summary|Url|Group|Source|BuildArch|BuildRequires|BuildRoot|AutoReqProv|Provides|Requires(\(\w+\))?|Obsoletes|Conflicts|Recommends|Source\d*|Patch\d*|ExclusiveArch|NoSource|Supplements):/;
Expand Down Expand Up @@ -63,4 +93,6 @@ CodeMirror.defineMode("spec", function() {
};
});

CodeMirror.defineMIME("text/x-rpm-spec", "spec");
CodeMirror.defineMIME("text/x-rpm-spec", "rpm-spec");

});
5 changes: 0 additions & 5 deletions mode/rpm/spec/spec.css

This file was deleted.

12 changes: 12 additions & 0 deletions mode/rst/rst.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../python/python"), require("../stex/stex"), require("../../addon/mode/overlay"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../python/python", "../stex/stex", "../../addon/mode/overlay"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode('rst', function (config, options) {

var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/;
Expand Down Expand Up @@ -561,3 +571,5 @@ CodeMirror.defineMIME('text/x-rst', 'rst');

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

});
11 changes: 11 additions & 0 deletions mode/ruby/ruby.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("ruby", function(config) {
function wordObj(words) {
var o = {};
Expand Down Expand Up @@ -248,3 +258,4 @@ CodeMirror.defineMode("ruby", function(config) {

CodeMirror.defineMIME("text/x-ruby", "ruby");

});
12 changes: 12 additions & 0 deletions mode/rust/rust.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("rust", function() {
var indentUnit = 4, altIndentUnit = 2;
var valKeywords = {
Expand Down Expand Up @@ -434,3 +444,5 @@ CodeMirror.defineMode("rust", function() {
});

CodeMirror.defineMIME("text/x-rustsrc", "rust");

});
12 changes: 12 additions & 0 deletions mode/sass/sass.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("sass", function(config) {
var tokenRegexp = function(words){
return new RegExp("^" + words.join("|"));
Expand Down Expand Up @@ -328,3 +338,5 @@ CodeMirror.defineMode("sass", function(config) {
});

CodeMirror.defineMIME("text/x-sass", "sass");

});
13 changes: 13 additions & 0 deletions mode/scheme/scheme.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
/**
* Author: Koh Zi Han, based on implementation by Koh Zi Chun
*/

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("scheme", function () {
var BUILTIN = "builtin", COMMENT = "comment", STRING = "string",
ATOM = "atom", NUMBER = "number", BRACKET = "bracket";
Expand Down Expand Up @@ -230,3 +241,5 @@ CodeMirror.defineMode("scheme", function () {
});

CodeMirror.defineMIME("text/x-scheme", "scheme");

});
12 changes: 12 additions & 0 deletions mode/shell/shell.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode('shell', function() {

var words = {};
Expand Down Expand Up @@ -116,3 +126,5 @@ CodeMirror.defineMode('shell', function() {
});

CodeMirror.defineMIME('text/x-sh', 'shell');

});
15 changes: 11 additions & 4 deletions mode/sieve/sieve.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/*
* See LICENSE in this directory for the license under which this code
* is released.
*/
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("sieve", function(config) {
function words(str) {
Expand Down Expand Up @@ -181,3 +186,5 @@ CodeMirror.defineMode("sieve", function(config) {
});

CodeMirror.defineMIME("application/sieve", "sieve");

});
12 changes: 12 additions & 0 deletions mode/smalltalk/smalltalk.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode('smalltalk', function(config) {

var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/;
Expand Down Expand Up @@ -151,3 +161,5 @@ CodeMirror.defineMode('smalltalk', function(config) {
});

CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});

});
13 changes: 13 additions & 0 deletions mode/smarty/smarty.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
/**
* Smarty 2 and 3 mode.
*/

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("smarty", function(config) {
"use strict";

Expand Down Expand Up @@ -203,3 +214,5 @@ CodeMirror.defineMode("smarty", function(config) {
});

CodeMirror.defineMIME("text/x-smarty", "smarty");

});
16 changes: 14 additions & 2 deletions mode/smartymixed/smartymixed.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
* @version 3.0
* @date 05.07.2013
*/

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../smarty/smarty"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../smarty/smarty"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("smartymixed", function(config) {
var settings, regs, helpers, parsers,
htmlMixedMode = CodeMirror.getMode(config, "htmlmixed"),
Expand Down Expand Up @@ -166,8 +177,9 @@ CodeMirror.defineMode("smartymixed", function(config) {
};
}
};
},
"htmlmixed");
}, "htmlmixed", "smarty");

CodeMirror.defineMIME("text/x-smarty", "smartymixed");
// vim: et ts=2 sts=2 sw=2

});
12 changes: 12 additions & 0 deletions mode/solr/solr.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("solr", function() {
"use strict";

Expand Down Expand Up @@ -87,3 +97,5 @@ CodeMirror.defineMode("solr", function() {
});

CodeMirror.defineMIME("text/x-solr", "solr");

});
12 changes: 12 additions & 0 deletions mode/sparql/sparql.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("sparql", function(config) {
var indentUnit = config.indentUnit;
var curPunc;
Expand Down Expand Up @@ -143,3 +153,5 @@ CodeMirror.defineMode("sparql", function(config) {
});

CodeMirror.defineMIME("application/x-sparql-query", "sparql");

});
12 changes: 12 additions & 0 deletions mode/sql/sql.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("sql", function(config, parserConfig) {
"use strict";

Expand Down Expand Up @@ -345,6 +355,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
});
}());

});

/*
How Properties of Mime Types are used by SQL Mode
=================================================
Expand Down
12 changes: 12 additions & 0 deletions mode/stex/stex.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
* Licence: MIT
*/

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("stex", function() {
"use strict";

Expand Down Expand Up @@ -244,3 +254,5 @@ CodeMirror.defineMode("stex", function() {

CodeMirror.defineMIME("text/x-stex", "stex");
CodeMirror.defineMIME("text/x-latex", "stex");

});
13 changes: 13 additions & 0 deletions mode/tcl/tcl.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
//tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("tcl", function() {
function parseWords(str) {
var obj = {}, words = str.split(" ");
Expand Down Expand Up @@ -129,3 +140,5 @@ CodeMirror.defineMode("tcl", function() {
};
});
CodeMirror.defineMIME("text/x-tcl", "tcl");

});
13 changes: 13 additions & 0 deletions mode/tiddlywiki/tiddlywiki.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@
CoreVersion parameter is needed for TiddlyWiki only!
***/
//{{{

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("tiddlywiki", function () {
// Tokenizer
var textwords = {};
Expand Down Expand Up @@ -350,4 +361,6 @@ CodeMirror.defineMode("tiddlywiki", function () {
});

CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki");
});

//}}}
12 changes: 12 additions & 0 deletions mode/tiki/tiki.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode('tiki', function(config) {
function inBlock(style, terminator, returnTokenizer) {
return function(stream, state) {
Expand Down Expand Up @@ -306,3 +316,5 @@ return {
});

CodeMirror.defineMIME("text/tiki", "tiki");

});
12 changes: 12 additions & 0 deletions mode/toml/toml.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("toml", function () {
return {
startState: function () {
Expand Down Expand Up @@ -71,3 +81,5 @@ CodeMirror.defineMode("toml", function () {
});

CodeMirror.defineMIME('text/x-toml', 'toml');

});
12 changes: 12 additions & 0 deletions mode/turtle/turtle.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("turtle", function(config) {
var indentUnit = config.indentUnit;
var curPunc;
Expand Down Expand Up @@ -143,3 +153,5 @@ CodeMirror.defineMode("turtle", function(config) {
});

CodeMirror.defineMIME("text/turtle", "turtle");

});
12 changes: 12 additions & 0 deletions mode/vb/vb.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("vb", function(conf, parserConf) {
var ERRORCLASS = 'error';

Expand Down Expand Up @@ -257,3 +267,5 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
});

CodeMirror.defineMIME("text/x-vb", "vb");

});
13 changes: 13 additions & 0 deletions mode/vbscript/vbscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ E.G.:
isASP: true
});
*/

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("vbscript", function(conf, parserConf) {
var ERRORCLASS = 'error';

Expand Down Expand Up @@ -332,3 +343,5 @@ CodeMirror.defineMode("vbscript", function(conf, parserConf) {
});

CodeMirror.defineMIME("text/vbscript", "vbscript");

});
12 changes: 12 additions & 0 deletions mode/velocity/velocity.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("velocity", function() {
function parseWords(str) {
var obj = {}, words = str.split(" ");
Expand Down Expand Up @@ -184,3 +194,5 @@ CodeMirror.defineMode("velocity", function() {
});

CodeMirror.defineMIME("text/velocity", "velocity");

});
14 changes: 12 additions & 2 deletions mode/verilog/verilog.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("verilog", function(config, parserConfig) {
var indentUnit = config.indentUnit,
keywords = parserConfig.keywords || {},
Expand Down Expand Up @@ -146,7 +156,6 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) {
};
});

(function() {
function words(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
Expand Down Expand Up @@ -179,4 +188,5 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) {
atoms: words("null"),
hooks: {"`": metaHook, "$": metaHook}
});
}());

});
13 changes: 13 additions & 0 deletions mode/xml/xml.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("xml", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
Expand Down Expand Up @@ -223,6 +233,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
return baseState;
}
}

function closeState(type, _stream, state) {
if (type != "endTag") {
setStyle = "error";
Expand Down Expand Up @@ -334,3 +345,5 @@ CodeMirror.defineMIME("text/xml", "xml");
CodeMirror.defineMIME("application/xml", "xml");
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});

});
12 changes: 12 additions & 0 deletions mode/xquery/xquery.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("xquery", function() {

// The keywords object is set to the result of this self executing
Expand Down Expand Up @@ -430,3 +440,5 @@ CodeMirror.defineMode("xquery", function() {
});

CodeMirror.defineMIME("application/xquery", "xquery");

});
12 changes: 12 additions & 0 deletions mode/yaml/yaml.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("yaml", function() {

var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
Expand Down Expand Up @@ -95,3 +105,5 @@ CodeMirror.defineMode("yaml", function() {
});

CodeMirror.defineMIME("text/x-yaml", "yaml");

});
12 changes: 12 additions & 0 deletions mode/z80/z80.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode('z80', function() {
var keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i;
var keywords2 = /^(call|j[pr]|ret[in]?)\b/i;
Expand Down Expand Up @@ -83,3 +93,5 @@ CodeMirror.defineMode('z80', function() {
});

CodeMirror.defineMIME("text/x-z80", "z80");

});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codemirror",
"version":"3.22.1",
"version":"4.0.3",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [{"type": "MIT",
Expand Down
19 changes: 19 additions & 0 deletions test/doc_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,25 @@
eq(cleared, 1);
});

testDoc("sharedBookmark", "A='ab\ncd\nef\ngh' B<A C<~A/1-2", function(a, b, c) {
var mark = b.setBookmark(Pos(1, 1), {shared: true});
var found = a.findMarksAt(Pos(1, 1));
eq(found.length, 1);
eq(found[0], mark);
eq(c.findMarksAt(Pos(1, 1)).length, 1);
eqPos(mark.find(), Pos(1, 1));
b.replaceRange("x\ny\n", Pos(0, 0));
eqPos(mark.find(), Pos(3, 1));
var cleared = 0;
CodeMirror.on(mark, "clear", function() {++cleared;});
b.operation(function() {mark.clear();});
eq(a.findMarks(Pos(0, 0), Pos(5)).length, 0);
eq(b.findMarks(Pos(0, 0), Pos(5)).length, 0);
eq(c.findMarks(Pos(0, 0), Pos(5)).length, 0);
eq(mark.find(), null);
eq(cleared, 1);
});

testDoc("undoInSubview", "A='line 0\nline 1\nline 2\nline 3\nline 4' B<A/1-4", function(a, b) {
b.replaceRange("x", Pos(2, 0));
a.undo();
Expand Down
33 changes: 20 additions & 13 deletions test/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,25 @@ function testCM(name, run, opts, expectedFail) {
function runTests(callback) {
var totalTime = 0;
function step(i) {
if (i === tests.length){
running = false;
return callback("done");
}
var test = tests[i], expFail = test.expectedFail, startTime = +new Date;
if (filters.length) {
for (var j = 0; j < filters.length; j++) {
if (test.name.match(filters[j])) {
break;
}
for (;;) {
if (i === tests.length) {
running = false;
return callback("done");
}
var test = tests[i], skip = false;
if (filters.length) {
skip = true;
for (var j = 0; j < filters.length; j++)
if (test.name.match(filters[j])) skip = false;
}
if (j == filters.length) {
if (skip) {
callback("skipped", test.name, message);
return step(i + 1);
i++;
} else {
break;
}
}
var threw = false;
var expFail = test.expectedFail, startTime = +new Date, threw = false;
try {
var message = test.func();
} catch(e) {
Expand All @@ -69,6 +71,7 @@ function runTests(callback) {
else if (e instanceof Failure) callback("fail", test.name, e.message);
else {
var pos = /(?:\bat |@).*?([^\/:]+):(\d+)/.exec(e.stack);
if (pos) console["log"](e.stack);
callback("error", test.name, e.toString() + (pos ? " (" + pos[1] + ":" + pos[2] + ")" : ""));
}
}
Expand Down Expand Up @@ -99,6 +102,10 @@ function label(str, msg) {
function eq(a, b, msg) {
if (a != b) throw new Failure(label(a + " != " + b, msg));
}
function near(a, b, margin, msg) {
if (Math.abs(a - b) > margin)
throw new Failure(label(a + " is not close to " + b + " (" + margin + ")", msg));
}
function eqPos(a, b, msg) {
function str(p) { return "{line:" + p.line + ",ch:" + p.ch + "}"; }
if (a == b) return;
Expand Down
4 changes: 4 additions & 0 deletions test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

<link rel="stylesheet" href="../lib/codemirror.css">
<link rel="stylesheet" href="mode_test.css">
<script src="../doc/activebookmark.js"></script>
<script src="../lib/codemirror.js"></script>
<script src="../addon/mode/overlay.js"></script>
<script src="../addon/mode/multiplex.js"></script>
Expand All @@ -17,6 +18,7 @@
<script src="../mode/xml/xml.js"></script>
<script src="../keymap/vim.js"></script>
<script src="../keymap/emacs.js"></script>
<script src="../keymap/sublime.js"></script>

<style type="text/css">
.ok {color: #090;}
Expand Down Expand Up @@ -71,6 +73,7 @@ <h2>Test Suite</h2>
<script src="driver.js"></script>
<script src="test.js"></script>
<script src="doc_test.js"></script>
<script src="multi_test.js"></script>
<script src="comment_test.js"></script>
<script src="search_test.js"></script>
<script src="mode_test.js"></script>
Expand All @@ -96,6 +99,7 @@ <h2>Test Suite</h2>
<script src="../addon/mode/multiplex_test.js"></script>
<script src="vim_test.js"></script>
<script src="emacs_test.js"></script>
<script src="sublime_test.js"></script>
<script>
window.onload = runHarness;
CodeMirror.on(window, 'hashchange', runHarness);
Expand Down
671 changes: 430 additions & 241 deletions test/lint/acorn.js

Large diffs are not rendered by default.

42 changes: 32 additions & 10 deletions test/lint/lint.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ var topAllowedGlobals = Object.create(null);
"window document navigator prompt alert confirm console " +
"FileReader Worker postMessage importScripts " +
"setInterval clearInterval setTimeout clearTimeout " +
"CodeMirror test")
"CodeMirror " +
"test exports require module define")
.split(" ").forEach(function(n) { topAllowedGlobals[n] = true; });

var fs = require("fs"), acorn = require("./acorn.js"), walk = require("./walk.js");
Expand Down Expand Up @@ -49,7 +50,7 @@ function checkFile(fileName) {
ecmaVersion: 3,
strictSemicolons: true,
allowTrailingCommas: false,
forbidReserved: true,
forbidReserved: "everywhere",
sourceFile: fileName
});
} catch (e) {
Expand Down Expand Up @@ -95,19 +96,40 @@ function checkFile(fileName) {
},
FunctionExpression: function(node) {
if (node.id) fail("Named function expression", node.loc);
},
ForStatement: function(node) {
checkReusedIndex(node);
},
MemberExpression: function(node) {
if (node.object.type == "Identifier" && node.object.name == "console" && !node.computed)
fail("Found console." + node.property.name, node.loc);
},
DebuggerStatement: function(node) {
fail("Found debugger statement", node.loc);
}
}, scopePasser);

if (!globalsSeen.exports) {
var allowedGlobals = Object.create(topAllowedGlobals), m;
if (m = file.match(/\/\/ declare global:\s+(.*)/))
m[1].split(/,\s*/g).forEach(function(n) { allowedGlobals[n] = true; });
for (var glob in globalsSeen)
if (!(glob in allowedGlobals))
fail("Access to global variable " + glob + ". Add a '// declare global: " + glob +
"' comment or add this variable in test/lint/lint.js.", globalsSeen[glob]);
function checkReusedIndex(node) {
if (!node.init || node.init.type != "VariableDeclaration") return;
var name = node.init.declarations[0].id.name;
walk.recursive(node.body, null, {
Function: function() {},
VariableDeclaration: function(node, st, c) {
for (var i = 0; i < node.declarations.length; i++)
if (node.declarations[i].id.name == name)
fail("redefined loop variable", node.declarations[i].id.loc);
walk.base.VariableDeclaration(node, st, c);
}
});
}

var allowedGlobals = Object.create(topAllowedGlobals), m;
if (m = file.match(/\/\/ declare global:\s+(.*)/))
m[1].split(/,\s*/g).forEach(function(n) { allowedGlobals[n] = true; });
for (var glob in globalsSeen)
if (!(glob in allowedGlobals))
fail("Access to global variable " + glob + ". Add a '// declare global: " + glob +
"' comment or add this variable in test/lint/lint.js.", globalsSeen[glob]);

for (var i = 0; i < scopes.length; ++i) {
var scope = scopes[i];
Expand Down
203 changes: 150 additions & 53 deletions test/lint/walk.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// AST walker module for Mozilla Parser API compatible trees

(function(exports) {
(function(mod) {
if (typeof exports == "object" && typeof module == "object") return mod(exports); // CommonJS
if (typeof define == "function" && define.amd) return define(["exports"], mod); // AMD
mod((this.acorn || (this.acorn = {})).walk = {}); // Plain browser env
})(function(exports) {
"use strict";

// A simple walk is one where you simply specify callbacks to be
Expand All @@ -19,11 +23,11 @@
// walker, and state can be used to give this walked an initial
// state.
exports.simple = function(node, visitors, base, state) {
if (!base) base = exports;
if (!base) base = exports.base;
function c(node, st, override) {
var type = override || node.type, found = visitors[type];
if (found) found(node, st);
base[type](node, st, c);
if (found) found(node, st);
}
c(node, state);
};
Expand All @@ -34,51 +38,140 @@
// their child nodes (by calling their third argument on these
// nodes).
exports.recursive = function(node, state, funcs, base) {
var visitor = exports.make(funcs, base);
var visitor = funcs ? exports.make(funcs, base) : base;
function c(node, st, override) {
visitor[override || node.type](node, st, c);
}
c(node, state);
};

function makeTest(test) {
if (typeof test == "string")
return function(type) { return type == test; };
else if (!test)
return function() { return true; };
else
return test;
}

function Found(node, state) { this.node = node; this.state = state; }

// Find a node with a given start, end, and type (all are optional,
// null can be used as wildcard). Returns a {node, state} object, or
// undefined when it doesn't find a matching node.
exports.findNodeAt = function(node, start, end, test, base, state) {
test = makeTest(test);
try {
if (!base) base = exports.base;
var c = function(node, st, override) {
var type = override || node.type;
if ((start == null || node.start <= start) &&
(end == null || node.end >= end))
base[type](node, st, c);
if (test(type, node) &&
(start == null || node.start == start) &&
(end == null || node.end == end))
throw new Found(node, st);
};
c(node, state);
} catch (e) {
if (e instanceof Found) return e;
throw e;
}
};

// Find the innermost node of a given type that contains the given
// position. Interface similar to findNodeAt.
exports.findNodeAround = function(node, pos, test, base, state) {
test = makeTest(test);
try {
if (!base) base = exports.base;
var c = function(node, st, override) {
var type = override || node.type;
if (node.start > pos || node.end < pos) return;
base[type](node, st, c);
if (test(type, node)) throw new Found(node, st);
};
c(node, state);
} catch (e) {
if (e instanceof Found) return e;
throw e;
}
};

// Find the outermost matching node after a given position.
exports.findNodeAfter = function(node, pos, test, base, state) {
test = makeTest(test);
try {
if (!base) base = exports.base;
var c = function(node, st, override) {
if (node.end < pos) return;
var type = override || node.type;
if (node.start >= pos && test(type, node)) throw new Found(node, st);
base[type](node, st, c);
};
c(node, state);
} catch (e) {
if (e instanceof Found) return e;
throw e;
}
};

// Find the outermost matching node before a given position.
exports.findNodeBefore = function(node, pos, test, base, state) {
test = makeTest(test);
if (!base) base = exports.base;
var max;
var c = function(node, st, override) {
if (node.start > pos) return;
var type = override || node.type;
if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))
max = new Found(node, st);
base[type](node, st, c);
};
c(node, state);
return max;
};

// Used to create a custom walker. Will fill in all missing node
// type properties with the defaults.
exports.make = function(funcs, base) {
if (!base) base = exports;
if (!base) base = exports.base;
var visitor = {};
for (var type in base)
visitor[type] = funcs.hasOwnProperty(type) ? funcs[type] : base[type];
for (var type in base) visitor[type] = base[type];
for (var type in funcs) visitor[type] = funcs[type];
return visitor;
};

function skipThrough(node, st, c) { c(node, st); }
function ignore(node, st, c) {}
function ignore(_node, _st, _c) {}

// Node walkers.

exports.Program = exports.BlockStatement = function(node, st, c) {
var base = exports.base = {};
base.Program = base.BlockStatement = function(node, st, c) {
for (var i = 0; i < node.body.length; ++i)
c(node.body[i], st, "Statement");
};
exports.Statement = skipThrough;
exports.EmptyStatement = ignore;
exports.ExpressionStatement = function(node, st, c) {
base.Statement = skipThrough;
base.EmptyStatement = ignore;
base.ExpressionStatement = function(node, st, c) {
c(node.expression, st, "Expression");
};
exports.IfStatement = function(node, st, c) {
base.IfStatement = function(node, st, c) {
c(node.test, st, "Expression");
c(node.consequent, st, "Statement");
if (node.alternate) c(node.alternate, st, "Statement");
};
exports.LabeledStatement = function(node, st, c) {
base.LabeledStatement = function(node, st, c) {
c(node.body, st, "Statement");
};
exports.BreakStatement = exports.ContinueStatement = ignore;
exports.WithStatement = function(node, st, c) {
base.BreakStatement = base.ContinueStatement = ignore;
base.WithStatement = function(node, st, c) {
c(node.object, st, "Expression");
c(node.body, st, "Statement");
};
exports.SwitchStatement = function(node, st, c) {
base.SwitchStatement = function(node, st, c) {
c(node.discriminant, st, "Expression");
for (var i = 0; i < node.cases.length; ++i) {
var cs = node.cases[i];
Expand All @@ -87,101 +180,104 @@
c(cs.consequent[j], st, "Statement");
}
};
exports.ReturnStatement = function(node, st, c) {
base.ReturnStatement = function(node, st, c) {
if (node.argument) c(node.argument, st, "Expression");
};
exports.ThrowStatement = function(node, st, c) {
base.ThrowStatement = function(node, st, c) {
c(node.argument, st, "Expression");
};
exports.TryStatement = function(node, st, c) {
base.TryStatement = function(node, st, c) {
c(node.block, st, "Statement");
for (var i = 0; i < node.handlers.length; ++i)
c(node.handlers[i].body, st, "ScopeBody");
if (node.handler) c(node.handler.body, st, "ScopeBody");
if (node.finalizer) c(node.finalizer, st, "Statement");
};
exports.WhileStatement = function(node, st, c) {
base.WhileStatement = function(node, st, c) {
c(node.test, st, "Expression");
c(node.body, st, "Statement");
};
exports.DoWhileStatement = exports.WhileStatement;
exports.ForStatement = function(node, st, c) {
base.DoWhileStatement = base.WhileStatement;
base.ForStatement = function(node, st, c) {
if (node.init) c(node.init, st, "ForInit");
if (node.test) c(node.test, st, "Expression");
if (node.update) c(node.update, st, "Expression");
c(node.body, st, "Statement");
};
exports.ForInStatement = function(node, st, c) {
base.ForInStatement = function(node, st, c) {
c(node.left, st, "ForInit");
c(node.right, st, "Expression");
c(node.body, st, "Statement");
};
exports.ForInit = function(node, st, c) {
base.ForInit = function(node, st, c) {
if (node.type == "VariableDeclaration") c(node, st);
else c(node, st, "Expression");
};
exports.DebuggerStatement = ignore;
base.DebuggerStatement = ignore;

exports.FunctionDeclaration = function(node, st, c) {
base.FunctionDeclaration = function(node, st, c) {
c(node, st, "Function");
};
exports.VariableDeclaration = function(node, st, c) {
base.VariableDeclaration = function(node, st, c) {
for (var i = 0; i < node.declarations.length; ++i) {
var decl = node.declarations[i];
if (decl.init) c(decl.init, st, "Expression");
}
};

exports.Function = function(node, st, c) {
base.Function = function(node, st, c) {
c(node.body, st, "ScopeBody");
};
exports.ScopeBody = function(node, st, c) {
base.ScopeBody = function(node, st, c) {
c(node, st, "Statement");
};

exports.Expression = skipThrough;
exports.ThisExpression = ignore;
exports.ArrayExpression = function(node, st, c) {
base.Expression = skipThrough;
base.ThisExpression = ignore;
base.ArrayExpression = function(node, st, c) {
for (var i = 0; i < node.elements.length; ++i) {
var elt = node.elements[i];
if (elt) c(elt, st, "Expression");
}
};
exports.ObjectExpression = function(node, st, c) {
base.ObjectExpression = function(node, st, c) {
for (var i = 0; i < node.properties.length; ++i)
c(node.properties[i].value, st, "Expression");
};
exports.FunctionExpression = exports.FunctionDeclaration;
exports.SequenceExpression = function(node, st, c) {
base.FunctionExpression = base.FunctionDeclaration;
base.SequenceExpression = function(node, st, c) {
for (var i = 0; i < node.expressions.length; ++i)
c(node.expressions[i], st, "Expression");
};
exports.UnaryExpression = exports.UpdateExpression = function(node, st, c) {
base.UnaryExpression = base.UpdateExpression = function(node, st, c) {
c(node.argument, st, "Expression");
};
exports.BinaryExpression = exports.AssignmentExpression = exports.LogicalExpression = function(node, st, c) {
base.BinaryExpression = base.AssignmentExpression = base.LogicalExpression = function(node, st, c) {
c(node.left, st, "Expression");
c(node.right, st, "Expression");
};
exports.ConditionalExpression = function(node, st, c) {
base.ConditionalExpression = function(node, st, c) {
c(node.test, st, "Expression");
c(node.consequent, st, "Expression");
c(node.alternate, st, "Expression");
};
exports.NewExpression = exports.CallExpression = function(node, st, c) {
base.NewExpression = base.CallExpression = function(node, st, c) {
c(node.callee, st, "Expression");
if (node.arguments) for (var i = 0; i < node.arguments.length; ++i)
c(node.arguments[i], st, "Expression");
};
exports.MemberExpression = function(node, st, c) {
base.MemberExpression = function(node, st, c) {
c(node.object, st, "Expression");
if (node.computed) c(node.property, st, "Expression");
};
exports.Identifier = exports.Literal = ignore;
base.Identifier = base.Literal = ignore;

// A custom walker that keeps track of the scope chain and the
// variables defined in it.
function makeScope(prev) {
return {vars: Object.create(null), prev: prev};
function makeScope(prev, isCatch) {
return {vars: Object.create(null), prev: prev, isCatch: isCatch};
}
function normalScope(scope) {
while (scope.isCatch) scope = scope.prev;
return scope;
}
exports.scopeVisitor = exports.make({
Function: function(node, scope, c) {
Expand All @@ -190,27 +286,28 @@
inner.vars[node.params[i].name] = {type: "argument", node: node.params[i]};
if (node.id) {
var decl = node.type == "FunctionDeclaration";
(decl ? scope : inner).vars[node.id.name] =
(decl ? normalScope(scope) : inner).vars[node.id.name] =
{type: decl ? "function" : "function name", node: node.id};
}
c(node.body, inner, "ScopeBody");
},
TryStatement: function(node, scope, c) {
c(node.block, scope, "Statement");
for (var i = 0; i < node.handlers.length; ++i) {
var handler = node.handlers[i], inner = makeScope(scope);
inner.vars[handler.param.name] = {type: "catch clause", node: handler.param};
c(handler.body, inner, "ScopeBody");
if (node.handler) {
var inner = makeScope(scope, true);
inner.vars[node.handler.param.name] = {type: "catch clause", node: node.handler.param};
c(node.handler.body, inner, "ScopeBody");
}
if (node.finalizer) c(node.finalizer, scope, "Statement");
},
VariableDeclaration: function(node, scope, c) {
var target = normalScope(scope);
for (var i = 0; i < node.declarations.length; ++i) {
var decl = node.declarations[i];
scope.vars[decl.id.name] = {type: "var", node: decl.id};
target.vars[decl.id.name] = {type: "var", node: decl.id};
if (decl.init) c(decl.init, scope, "Expression");
}
}
});

})(typeof exports == "undefined" ? acorn.walk = {} : exports);
});
285 changes: 285 additions & 0 deletions test/multi_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
(function() {
namespace = "multi_";

function hasSelections(cm) {
var sels = cm.listSelections();
var given = (arguments.length - 1) / 4;
if (sels.length != given)
throw new Failure("expected " + given + " selections, found " + sels.length);
for (var i = 0, p = 1; i < given; i++, p += 4) {
var anchor = Pos(arguments[p], arguments[p + 1]);
var head = Pos(arguments[p + 2], arguments[p + 3]);
eqPos(sels[i].anchor, anchor, "anchor of selection " + i);
eqPos(sels[i].head, head, "head of selection " + i);
}
}
function hasCursors(cm) {
var sels = cm.listSelections();
var given = (arguments.length - 1) / 2;
if (sels.length != given)
throw new Failure("expected " + given + " selections, found " + sels.length);
for (var i = 0, p = 1; i < given; i++, p += 2) {
eqPos(sels[i].anchor, sels[i].head, "something selected for " + i);
var head = Pos(arguments[p], arguments[p + 1]);
eqPos(sels[i].head, head, "selection " + i);
}
}

testCM("getSelection", function(cm) {
select(cm, {anchor: Pos(0, 0), head: Pos(1, 2)}, {anchor: Pos(2, 2), head: Pos(2, 0)});
eq(cm.getSelection(), "1234\n56\n90");
eq(cm.getSelection(false).join("|"), "1234|56|90");
eq(cm.getSelections().join("|"), "1234\n56|90");
}, {value: "1234\n5678\n90"});

testCM("setSelection", function(cm) {
select(cm, Pos(3, 0), Pos(0, 0), {anchor: Pos(2, 5), head: Pos(1, 0)});
hasSelections(cm, 0, 0, 0, 0,
2, 5, 1, 0,
3, 0, 3, 0);
cm.setSelection(Pos(1, 2), Pos(1, 1));
hasSelections(cm, 1, 2, 1, 1);
select(cm, {anchor: Pos(1, 1), head: Pos(2, 4)},
{anchor: Pos(0, 0), head: Pos(1, 3)},
Pos(3, 0), Pos(2, 2));
hasSelections(cm, 0, 0, 2, 4,
3, 0, 3, 0);
cm.setSelections([{anchor: Pos(0, 1), head: Pos(0, 2)},
{anchor: Pos(1, 1), head: Pos(1, 2)},
{anchor: Pos(2, 1), head: Pos(2, 2)}], 1);
eqPos(cm.getCursor("head"), Pos(1, 2));
eqPos(cm.getCursor("anchor"), Pos(1, 1));
eqPos(cm.getCursor("from"), Pos(1, 1));
eqPos(cm.getCursor("to"), Pos(1, 2));
cm.setCursor(Pos(1, 1));
hasCursors(cm, 1, 1);
}, {value: "abcde\nabcde\nabcde\n"});

testCM("somethingSelected", function(cm) {
select(cm, Pos(0, 1), {anchor: Pos(0, 3), head: Pos(0, 5)});
eq(cm.somethingSelected(), true);
select(cm, Pos(0, 1), Pos(0, 3), Pos(0, 5));
eq(cm.somethingSelected(), false);
}, {value: "123456789"});

testCM("extendSelection", function(cm) {
select(cm, Pos(0, 1), Pos(1, 1), Pos(2, 1));
cm.setExtending(true);
cm.extendSelections([Pos(0, 2), Pos(1, 0), Pos(2, 3)]);
hasSelections(cm, 0, 1, 0, 2,
1, 1, 1, 0,
2, 1, 2, 3);
cm.extendSelection(Pos(2, 4), Pos(2, 0));
hasSelections(cm, 2, 4, 2, 0);
}, {value: "1234\n1234\n1234"});

testCM("addSelection", function(cm) {
select(cm, Pos(0, 1), Pos(1, 1));
cm.addSelection(Pos(0, 0), Pos(0, 4));
hasSelections(cm, 0, 0, 0, 4,
1, 1, 1, 1);
cm.addSelection(Pos(2, 2));
hasSelections(cm, 0, 0, 0, 4,
1, 1, 1, 1,
2, 2, 2, 2);
}, {value: "1234\n1234\n1234"});

testCM("replaceSelection", function(cm) {
var selections = [{anchor: Pos(0, 0), head: Pos(0, 1)},
{anchor: Pos(0, 2), head: Pos(0, 3)},
{anchor: Pos(0, 4), head: Pos(0, 5)},
{anchor: Pos(2, 1), head: Pos(2, 4)},
{anchor: Pos(2, 5), head: Pos(2, 6)}];
var val = "123456\n123456\n123456";
cm.setValue(val);
cm.setSelections(selections);
cm.replaceSelection("ab", "around");
eq(cm.getValue(), "ab2ab4ab6\n123456\n1ab5ab");
hasSelections(cm, 0, 0, 0, 2,
0, 3, 0, 5,
0, 6, 0, 8,
2, 1, 2, 3,
2, 4, 2, 6);
cm.setValue(val);
cm.setSelections(selections);
cm.replaceSelection("", "around");
eq(cm.getValue(), "246\n123456\n15");
hasSelections(cm, 0, 0, 0, 0,
0, 1, 0, 1,
0, 2, 0, 2,
2, 1, 2, 1,
2, 2, 2, 2);
cm.setValue(val);
cm.setSelections(selections);
cm.replaceSelection("X\nY\nZ", "around");
hasSelections(cm, 0, 0, 2, 1,
2, 2, 4, 1,
4, 2, 6, 1,
8, 1, 10, 1,
10, 2, 12, 1);
cm.replaceSelection("a", "around");
hasSelections(cm, 0, 0, 0, 1,
0, 2, 0, 3,
0, 4, 0, 5,
2, 1, 2, 2,
2, 3, 2, 4);
cm.replaceSelection("xy", "start");
hasSelections(cm, 0, 0, 0, 0,
0, 3, 0, 3,
0, 6, 0, 6,
2, 1, 2, 1,
2, 4, 2, 4);
cm.replaceSelection("z\nf");
hasSelections(cm, 1, 1, 1, 1,
2, 1, 2, 1,
3, 1, 3, 1,
6, 1, 6, 1,
7, 1, 7, 1);
eq(cm.getValue(), "z\nfxy2z\nfxy4z\nfxy6\n123456\n1z\nfxy5z\nfxy");
});

function select(cm) {
var sels = [];
for (var i = 1; i < arguments.length; i++) {
var arg = arguments[i];
if (arg.head) sels.push(arg);
else sels.push({head: arg, anchor: arg});
}
cm.setSelections(sels, sels.length - 1);
}

testCM("indentSelection", function(cm) {
select(cm, Pos(0, 1), Pos(1, 1));
cm.indentSelection(4);
eq(cm.getValue(), " foo\n bar\nbaz");

select(cm, Pos(0, 2), Pos(0, 3), Pos(0, 4));
cm.indentSelection(-2);
eq(cm.getValue(), " foo\n bar\nbaz");

select(cm, {anchor: Pos(0, 0), head: Pos(1, 2)},
{anchor: Pos(1, 3), head: Pos(2, 0)});
cm.indentSelection(-2);
eq(cm.getValue(), "foo\n bar\nbaz");
}, {value: "foo\nbar\nbaz"});

testCM("killLine", function(cm) {
select(cm, Pos(0, 1), Pos(0, 2), Pos(1, 1));
cm.execCommand("killLine");
eq(cm.getValue(), "f\nb\nbaz");
cm.execCommand("killLine");
eq(cm.getValue(), "fbbaz");
cm.setValue("foo\nbar\nbaz");
select(cm, Pos(0, 1), {anchor: Pos(0, 2), head: Pos(2, 1)});
cm.execCommand("killLine");
eq(cm.getValue(), "faz");
}, {value: "foo\nbar\nbaz"});

testCM("deleteLine", function(cm) {
select(cm, Pos(0, 0),
{head: Pos(0, 1), anchor: Pos(2, 0)},
Pos(4, 0));
cm.execCommand("deleteLine");
eq(cm.getValue(), "4\n6\n7");
select(cm, Pos(2, 1));
cm.execCommand("deleteLine");
eq(cm.getValue(), "4\n6\n");
}, {value: "1\n2\n3\n4\n5\n6\n7"});

testCM("deleteH", function(cm) {
select(cm, Pos(0, 4), {anchor: Pos(1, 4), head: Pos(1, 5)});
cm.execCommand("delWordAfter");
eq(cm.getValue(), "foo bar baz\nabc ef ghi\n");
cm.execCommand("delWordAfter");
eq(cm.getValue(), "foo baz\nabc ghi\n");
cm.execCommand("delCharBefore");
cm.execCommand("delCharBefore");
eq(cm.getValue(), "fo baz\nab ghi\n");
select(cm, Pos(0, 3), Pos(0, 4), Pos(0, 5));
cm.execCommand("delWordAfter");
eq(cm.getValue(), "fo \nab ghi\n");
}, {value: "foo bar baz\nabc def ghi\n"});

testCM("goLineStart", function(cm) {
select(cm, Pos(0, 2), Pos(0, 3), Pos(1, 1));
cm.execCommand("goLineStart");
hasCursors(cm, 0, 0, 1, 0);
select(cm, Pos(1, 1), Pos(0, 1));
cm.setExtending(true);
cm.execCommand("goLineStart");
hasSelections(cm, 0, 1, 0, 0,
1, 1, 1, 0);
}, {value: "foo\nbar\nbaz"});

testCM("moveV", function(cm) {
select(cm, Pos(0, 2), Pos(1, 2));
cm.execCommand("goLineDown");
hasCursors(cm, 1, 2, 2, 2);
cm.execCommand("goLineUp");
hasCursors(cm, 0, 2, 1, 2);
cm.execCommand("goLineUp");
hasCursors(cm, 0, 0, 0, 2);
cm.execCommand("goLineUp");
hasCursors(cm, 0, 0);
select(cm, Pos(0, 2), Pos(1, 2));
cm.setExtending(true);
cm.execCommand("goLineDown");
hasSelections(cm, 0, 2, 2, 2);
}, {value: "12345\n12345\n12345"});

testCM("moveH", function(cm) {
select(cm, Pos(0, 1), Pos(0, 3), Pos(0, 5), Pos(2, 3));
cm.execCommand("goCharRight");
hasCursors(cm, 0, 2, 0, 4, 1, 0, 2, 4);
cm.execCommand("goCharLeft");
hasCursors(cm, 0, 1, 0, 3, 0, 5, 2, 3);
for (var i = 0; i < 15; i++)
cm.execCommand("goCharRight");
hasCursors(cm, 2, 4, 2, 5);
}, {value: "12345\n12345\n12345"});

testCM("newlineAndIndent", function(cm) {
select(cm, Pos(0, 5), Pos(1, 5));
cm.execCommand("newlineAndIndent");
hasCursors(cm, 1, 2, 3, 2);
eq(cm.getValue(), "x = [\n 1];\ny = [\n 2];");
cm.undo();
eq(cm.getValue(), "x = [1];\ny = [2];");
hasCursors(cm, 0, 5, 1, 5);
select(cm, Pos(0, 5), Pos(0, 6));
cm.execCommand("newlineAndIndent");
hasCursors(cm, 1, 2, 2, 0);
eq(cm.getValue(), "x = [\n 1\n];\ny = [2];");
}, {value: "x = [1];\ny = [2];", mode: "javascript"});

testCM("goDocStartEnd", function(cm) {
select(cm, Pos(0, 1), Pos(1, 1));
cm.execCommand("goDocStart");
hasCursors(cm, 0, 0);
select(cm, Pos(0, 1), Pos(1, 1));
cm.execCommand("goDocEnd");
hasCursors(cm, 1, 3);
select(cm, Pos(0, 1), Pos(1, 1));
cm.setExtending(true);
cm.execCommand("goDocEnd");
hasSelections(cm, 1, 1, 1, 3);
}, {value: "abc\ndef"});

testCM("selectionHistory", function(cm) {
for (var i = 0; i < 3; ++i)
cm.addSelection(Pos(0, i * 2), Pos(0, i * 2 + 1));
cm.execCommand("undoSelection");
eq(cm.getSelection(), "1\n2");
cm.execCommand("undoSelection");
eq(cm.getSelection(), "1");
cm.execCommand("undoSelection");
eq(cm.getSelection(), "");
eqPos(cm.getCursor(), Pos(0, 0));
cm.execCommand("redoSelection");
eq(cm.getSelection(), "1");
cm.execCommand("redoSelection");
eq(cm.getSelection(), "1\n2");
cm.execCommand("redoSelection");
eq(cm.getSelection(), "1\n2\n3");
}, {value: "1 2 3"});
})();
297 changes: 297 additions & 0 deletions test/sublime_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
(function() {
"use strict";

var Pos = CodeMirror.Pos;
namespace = "sublime_";

function stTest(name) {
var actions = Array.prototype.slice.call(arguments, 1);
testCM(name, function(cm) {
for (var i = 0; i < actions.length; i++) {
var action = actions[i];
if (typeof action == "string" && i == 0)
cm.setValue(action);
else if (typeof action == "string")
cm.execCommand(action);
else if (action instanceof Pos)
cm.setCursor(action);
else
action(cm);
}
});
}

function at(line, ch, msg) {
return function(cm) {
eq(cm.listSelections().length, 1);
eqPos(cm.getCursor("head"), Pos(line, ch), msg);
eqPos(cm.getCursor("anchor"), Pos(line, ch), msg);
};
}

function val(content, msg) {
return function(cm) { eq(cm.getValue(), content, msg); };
}

function argsToRanges(args) {
if (args.length % 4) throw new Error("Wrong number of arguments for ranges.");
var ranges = [];
for (var i = 0; i < args.length; i += 4)
ranges.push({anchor: Pos(args[i], args[i + 1]),
head: Pos(args[i + 2], args[i + 3])});
return ranges;
}

function setSel() {
var ranges = argsToRanges(arguments);
return function(cm) { cm.setSelections(ranges, 0); };
}

function hasSel() {
var ranges = argsToRanges(arguments);
return function(cm) {
var sels = cm.listSelections();
if (sels.length != ranges.length)
throw new Failure("Expected " + ranges.length + " selections, but found " + sels.length);
for (var i = 0; i < sels.length; i++) {
eqPos(sels[i].anchor, ranges[i].anchor, "anchor " + i);
eqPos(sels[i].head, ranges[i].head, "head " + i);
}
};
}

stTest("bySubword", "the foo_bar DooDahBah \n a",
"goSubwordLeft", at(0, 0),
"goSubwordRight", at(0, 3),
"goSubwordRight", at(0, 7),
"goSubwordRight", at(0, 11),
"goSubwordRight", at(0, 15),
"goSubwordRight", at(0, 18),
"goSubwordRight", at(0, 21),
"goSubwordRight", at(0, 22),
"goSubwordRight", at(1, 0),
"goSubwordRight", at(1, 2),
"goSubwordRight", at(1, 2),
"goSubwordLeft", at(1, 1),
"goSubwordLeft", at(1, 0),
"goSubwordLeft", at(0, 22),
"goSubwordLeft", at(0, 18),
"goSubwordLeft", at(0, 15),
"goSubwordLeft", at(0, 12),
"goSubwordLeft", at(0, 8),
"goSubwordLeft", at(0, 4),
"goSubwordLeft", at(0, 0));

stTest("splitSelectionByLine", "abc\ndef\nghi",
setSel(0, 1, 2, 2),
"splitSelectionByLine",
hasSel(0, 1, 0, 3,
1, 0, 1, 3,
2, 0, 2, 2));

stTest("splitSelectionByLineMulti", "abc\ndef\nghi\njkl",
setSel(0, 1, 1, 1,
1, 2, 3, 2,
3, 3, 3, 3),
"splitSelectionByLine",
hasSel(0, 1, 0, 3,
1, 0, 1, 1,
1, 2, 1, 3,
2, 0, 2, 3,
3, 0, 3, 2,
3, 3, 3, 3));

stTest("selectLine", "abc\ndef\nghi",
setSel(0, 1, 0, 1,
2, 0, 2, 1),
"selectLine",
hasSel(0, 0, 1, 0,
2, 0, 2, 3),
setSel(0, 1, 1, 0),
"selectLine",
hasSel(0, 0, 2, 0));

stTest("insertLineAfter", "abcde\nfghijkl\nmn",
setSel(0, 1, 0, 1,
0, 3, 0, 3,
1, 2, 1, 2,
1, 3, 1, 5), "insertLineAfter",
hasSel(1, 0, 1, 0,
3, 0, 3, 0), val("abcde\n\nfghijkl\n\nmn"));

stTest("insertLineBefore", "abcde\nfghijkl\nmn",
setSel(0, 1, 0, 1,
0, 3, 0, 3,
1, 2, 1, 2,
1, 3, 1, 5), "insertLineBefore",
hasSel(0, 0, 0, 0,
2, 0, 2, 0), val("\nabcde\n\nfghijkl\nmn"));

stTest("selectNextOccurrence", "a foo bar\nfoobar foo",
setSel(0, 2, 0, 5),
"selectNextOccurrence", hasSel(0, 2, 0, 5,
1, 0, 1, 3),
"selectNextOccurrence", hasSel(0, 2, 0, 5,
1, 0, 1, 3,
1, 7, 1, 10),
"selectNextOccurrence", hasSel(0, 2, 0, 5,
1, 0, 1, 3,
1, 7, 1, 10),
Pos(0, 3), "selectNextOccurrence", hasSel(0, 2, 0, 5),
"selectNextOccurrence", hasSel(0, 2, 0, 5,
1, 7, 1, 10),
setSel(0, 6, 0, 9),
"selectNextOccurrence", hasSel(0, 6, 0, 9,
1, 3, 1, 6));

stTest("selectScope", "foo(a) {\n bar[1, 2];\n}",
"selectScope", hasSel(0, 0, 2, 1),
Pos(0, 4), "selectScope", hasSel(0, 4, 0, 5),
Pos(0, 5), "selectScope", hasSel(0, 4, 0, 5),
Pos(0, 6), "selectScope", hasSel(0, 0, 2, 1),
Pos(0, 8), "selectScope", hasSel(0, 8, 2, 0),
Pos(1, 2), "selectScope", hasSel(0, 8, 2, 0),
Pos(1, 6), "selectScope", hasSel(1, 6, 1, 10),
Pos(1, 9), "selectScope", hasSel(1, 6, 1, 10));

stTest("goToBracket", "foo(a) {\n bar[1, 2];\n}",
Pos(0, 0), "goToBracket", at(0, 0),
Pos(0, 4), "goToBracket", at(0, 5), "goToBracket", at(0, 4),
Pos(0, 8), "goToBracket", at(2, 0), "goToBracket", at(0, 8),
Pos(1, 2), "goToBracket", at(2, 0),
Pos(1, 7), "goToBracket", at(1, 10), "goToBracket", at(1, 6));

stTest("swapLine", "1\n2\n3---\n4\n5",
"swapLineDown", val("2\n1\n3---\n4\n5"),
"swapLineUp", val("1\n2\n3---\n4\n5"),
"swapLineUp", val("1\n2\n3---\n4\n5"),
Pos(4, 1), "swapLineDown", val("1\n2\n3---\n4\n5"),
setSel(0, 1, 0, 1,
1, 0, 2, 0,
2, 2, 2, 2),
"swapLineDown", val("4\n1\n2\n3---\n5"),
hasSel(1, 1, 1, 1,
2, 0, 3, 0,
3, 2, 3, 2),
"swapLineUp", val("1\n2\n3---\n4\n5"),
hasSel(0, 1, 0, 1,
1, 0, 2, 0,
2, 2, 2, 2));

stTest("swapLineUpFromEnd", "a\nb\nc",
Pos(2, 1), "swapLineUp",
hasSel(1, 1, 1, 1), val("a\nc\nb"));

stTest("joinLines", "abc\ndef\nghi\njkl",
"joinLines", val("abc def\nghi\njkl"), at(0, 4),
"undo",
setSel(0, 2, 1, 1), "joinLines",
val("abc def ghi\njkl"), hasSel(0, 2, 0, 8),
"undo",
setSel(0, 1, 0, 1,
1, 1, 1, 1,
3, 1, 3, 1), "joinLines",
val("abc def ghi\njkl"), hasSel(0, 4, 0, 4,
0, 8, 0, 8,
1, 3, 1, 3));

stTest("duplicateLine", "abc\ndef\nghi",
Pos(1, 0), "duplicateLine", val("abc\ndef\ndef\nghi"), at(2, 0),
"undo",
setSel(0, 1, 0, 1,
1, 1, 1, 1,
2, 1, 2, 1), "duplicateLine",
val("abc\nabc\ndef\ndef\nghi\nghi"), hasSel(1, 1, 1, 1,
3, 1, 3, 1,
5, 1, 5, 1));
stTest("duplicateLineSelection", "abcdef",
setSel(0, 1, 0, 1,
0, 2, 0, 4,
0, 5, 0, 5),
"duplicateLine",
val("abcdef\nabcdcdef\nabcdcdef"), hasSel(2, 1, 2, 1,
2, 4, 2, 6,
2, 7, 2, 7));

stTest("selectLinesUpward", "123\n345\n789\n012",
setSel(0, 1, 0, 1,
1, 1, 1, 3,
2, 0, 2, 0,
3, 0, 3, 0),
"selectLinesUpward",
hasSel(0, 1, 0, 1,
0, 3, 0, 3,
1, 0, 1, 0,
1, 1, 1, 3,
2, 0, 2, 0,
3, 0, 3, 0));

stTest("selectLinesDownward", "123\n345\n789\n012",
setSel(0, 1, 0, 1,
1, 1, 1, 3,
2, 0, 2, 0,
3, 0, 3, 0),
"selectLinesDownward",
hasSel(0, 1, 0, 1,
1, 1, 1, 3,
2, 0, 2, 0,
2, 3, 2, 3,
3, 0, 3, 0));

stTest("sortLines", "c\nb\na\nC\nB\nA",
"sortLines", val("A\nB\nC\na\nb\nc"),
"undo",
setSel(0, 0, 2, 0,
3, 0, 5, 0),
"sortLines", val("a\nb\nc\nA\nB\nC"),
hasSel(0, 0, 2, 1,
3, 0, 5, 1),
"undo",
setSel(1, 0, 4, 0), "sortLinesInsensitive", val("c\na\nB\nb\nC\nA"));

stTest("bookmarks", "abc\ndef\nghi\njkl",
Pos(0, 1), "toggleBookmark",
setSel(1, 1, 1, 2), "toggleBookmark",
setSel(2, 1, 2, 2), "toggleBookmark",
"nextBookmark", hasSel(0, 1, 0, 1),
"nextBookmark", hasSel(1, 1, 1, 2),
"nextBookmark", hasSel(2, 1, 2, 2),
"prevBookmark", hasSel(1, 1, 1, 2),
"prevBookmark", hasSel(0, 1, 0, 1),
"prevBookmark", hasSel(2, 1, 2, 2),
"prevBookmark", hasSel(1, 1, 1, 2),
"toggleBookmark",
"prevBookmark", hasSel(2, 1, 2, 2),
"prevBookmark", hasSel(0, 1, 0, 1),
"selectBookmarks", hasSel(0, 1, 0, 1,
2, 1, 2, 2),
"clearBookmarks",
Pos(0, 0), "selectBookmarks", at(0, 0));

stTest("upAndDowncaseAtCursor", "abc\ndef x\nghI",
setSel(0, 1, 0, 3,
1, 1, 1, 1,
1, 4, 1, 4), "upcaseAtCursor",
val("aBC\nDEF x\nghI"), hasSel(0, 1, 0, 3,
1, 3, 1, 3,
1, 4, 1, 4),
"downcaseAtCursor",
val("abc\ndef x\nghI"), hasSel(0, 1, 0, 3,
1, 3, 1, 3,
1, 4, 1, 4));

stTest("mark", "abc\ndef\nghi",
Pos(1, 1), "setSublimeMark",
Pos(2, 1), "selectToSublimeMark", hasSel(2, 1, 1, 1),
Pos(0, 1), "swapWithSublimeMark", at(1, 1), "swapWithSublimeMark", at(0, 1),
"deleteToSublimeMark", val("aef\nghi"),
"sublimeYank", val("abc\ndef\nghi"), at(1, 1));

stTest("findUnder", "foo foobar a",
"findUnder", hasSel(0, 4, 0, 7),
"findUnder", hasSel(0, 0, 0, 3),
"findUnderPrevious", hasSel(0, 4, 0, 7),
"findUnderPrevious", hasSel(0, 0, 0, 3),
Pos(0, 4), "findUnder", hasSel(0, 4, 0, 10),
Pos(0, 11), "findUnder", hasSel(0, 11, 0, 11));
})();
306 changes: 248 additions & 58 deletions test/test.js

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions test/vim_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,12 @@ testVim('<<', function(cm, vim, helpers) {
// Edit tests
function testEdit(name, before, pos, edit, after) {
return testVim(name, function(cm, vim, helpers) {
cm.setCursor(0, before.search(pos));
var ch = before.search(pos)
var line = before.substring(0, ch).split('\n').length - 1;
if (line) {
ch = before.substring(0, ch).split('\n').pop().length;
}
cm.setCursor(line, ch);
helpers.doKeys.apply(this, edit.split(''));
eq(after, cm.getValue());
}, {value: before});
Expand Down Expand Up @@ -2243,7 +2248,7 @@ testVim('scrollMotion', function(cm, vim, helpers){
prevScrollInfo = cm.getScrollInfo();
helpers.doKeys('<C-e>');
eq(1, cm.getCursor().line);
eq(true, prevScrollInfo.top < cm.getScrollInfo().top);
is(prevScrollInfo.top < cm.getScrollInfo().top);
// Jump to the end of the sandbox.
cm.setCursor(1000, 0);
prevCursor = cm.getCursor();
Expand All @@ -2253,7 +2258,7 @@ testVim('scrollMotion', function(cm, vim, helpers){
prevScrollInfo = cm.getScrollInfo();
helpers.doKeys('<C-y>');
eq(prevCursor.line - 1, cm.getCursor().line);
eq(true, prevScrollInfo.top > cm.getScrollInfo().top);
is(prevScrollInfo.top > cm.getScrollInfo().top);
}, { value: scrollMotionSandbox});

var squareBracketMotionSandbox = ''+
Expand Down Expand Up @@ -2846,3 +2851,9 @@ testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) {
helpers.assertCursorAt(0, 0);
eq('bc', cm.getValue());
}, { value: 'abc' });

// Test event handlers
testVim('beforeSelectionChange', function(cm, vim, helpers) {
cm.setCursor(0, 100);
eqPos(cm.getCursor('head'), cm.getCursor('anchor'));
}, { value: 'abc' });