Initial import of complete codemirror

This commit is contained in:
Michal Čihař 2011-06-02 13:40:19 +02:00
parent 2da400447c
commit 0968f5bb60
61 changed files with 9013 additions and 0 deletions

19
js/codemirror/LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (C) 2011 by Marijn Haverbeke <marijnh@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

6
js/codemirror/README.md Normal file
View File

@ -0,0 +1,6 @@
# CodeMirror 2
CodeMirror 2 is a rewrite of [CodeMirror
1](http://github.com/marijnh/CodeMirror). The docs live
[here](http://codemirror.net/2/manual.html), and the project page is
[http://codemirror.net/2/](http://codemirror.net/2/).

View File

@ -0,0 +1,83 @@
<!doctype html>
<html>
<head>
<title>CodeMirror: Compression Helper</title>
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
<pre class="grey">
<img src="css/baboon.png" class="logo" alt="logo"/>/* Script compression
helper */
</pre>
<p>To optimize loading CodeMirror, especially when including a
bunch of different modes, it is recommended that you combine and
minify (and preferably also gzip) the scripts. This page makes
those first two steps very easy. Simply select the version and
scripts you need in the form below, and
click <strong>Compress</strong> to download the minified script
file.</p>
<form id="form" action="http://marijnhaverbeke.nl/uglifyjs" method="post">
<input type="hidden" id="download" name="download" value="codemirror-compressed.js"/>
<p>Version: <select id="version" onchange="setVersion(this);" style="padding: 1px">
<option value="http://codemirror.net/">HEAD</option>
<option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.01;f=">2.01</option>
<option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.0;f=">2.0</option>
<option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=beta2;f=">beta2</option>
<option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=beta1;f=">beta1</option>
</select></p>
<select multiple="multiple" name="code_url" style="width: 40em;" class="field" id="files">
<optgroup label="CodeMirror Library">
<option value="http://codemirror.net/lib/codemirror.js" selected>codemirror.js</option>
<option value="http://codemirror.net/lib/overlay.js">overlay.js</option>
</optgroup>
<optgroup label="Modes">
<option value="http://codemirror.net/mode/javascript/javascript.js">javascript.js</option>
<option value="http://codemirror.net/mode/xml/xml.js">xml.js</option>
<option value="http://codemirror.net/mode/css/css.js">css.js</option>
<option value="http://codemirror.net/mode/htmlmixed/htmlmixed.js">htmlmixed.js</option>
<option value="http://codemirror.net/mode/clike/clike.js">clike.js</option>
<option value="http://codemirror.net/mode/python/python.js">python.js</option>
<option value="http://codemirror.net/mode/php/php.js">php.js</option>
<option value="http://codemirror.net/mode/haskell/haskell.js">haskell.js</option>
<option value="http://codemirror.net/mode/diff/diff.js">diff.js</option>
<option value="http://codemirror.net/mode/stex/stex.js">stex.js</option>
<option value="http://codemirror.net/mode/smalltalk/smalltalk.js">smalltalk.js</option>
<option value="http://codemirror.net/mode/rst/rst.js">rst.js</option>
<option value="http://codemirror.net/mode/plsql/plsql.js">plsql.js</option>
</optgroup>
</select></p>
<p>
<button type="submit">Compress</button> with <a href="http://github.com/mishoo/UglifyJS/">UglifyJS</a>
</p>
<p>Custom code to add to the compressed file:<textarea name="js_code" style="width: 100%; height: 15em;" class="field"></textarea></p>
</form>
<script type="text/javascript">
function setVersion(ver) {
var urlprefix = ver.options[ver.selectedIndex].value;
var select = document.getElementById("files"), m;
for (var optgr = select.firstChild; optgr; optgr = optgr.nextSibling)
for (var opt = optgr.firstChild; opt; opt = opt.nextSibling) {
if (opt.nodeName != "OPTION")
continue;
else if (m = opt.value.match(/^http:\/\/codemirror.net\/2\/(.*)$/))
opt.value = urlprefix + m[1];
else if (m = opt.value.match(/http:\/\/marijnhaverbeke.nl\/git\/codemirror\?a=blob_plain;hb=[^;]+;f=(.*)$/))
opt.value = urlprefix + m[1];
}
}
</script>
<script type="text/javascript" src="css/font.js"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

157
js/codemirror/css/docs.css Normal file
View File

@ -0,0 +1,157 @@
body {
font-family: Arial, sans-serif;
line-height: 1.5;
max-width: 64.3em;
margin: 3em auto;
padding: 0 1em;
}
body.droid {
font-family: Droid Sans, Arial, sans-serif;
}
h1 {
letter-spacing: -3px;
font-size: 3.23em;
font-weight: bold;
margin: 0;
}
h2 {
font-size: 1.23em;
font-weight: bold;
margin: .5em 0;
letter-spacing: -1px;
}
h3 {
font-size: 1em;
font-weight: bold;
margin: .4em 0;
}
pre {
background-color: #eee;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
padding: 1em;
}
pre.code {
margin: 0 1em;
}
.grey {
font-size: 2.2em;
padding: .5em 1em;
line-height: 1.2em;
margin-top: .5em;
position: relative;
}
img.logo {
position: absolute;
right: -25px;
bottom: 4px;
}
a:link, a:visited, .quasilink {
color: #df0019;
cursor: pointer;
text-decoration: none;
}
a:hover, .quasilink:hover {
color: #800004;
}
h1 a:link, h1 a:visited, h1 a:hover {
color: black;
}
ul {
margin: 0;
padding-left: 1.2em;
}
a.download {
color: white;
background-color: #df0019;
width: 100%;
display: block;
text-align: center;
font-size: 1.23em;
font-weight: bold;
text-decoration: none;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
padding: .5em 0;
margin-bottom: 1em;
}
a.download:hover {
background-color: #bb0010;
}
.rel {
margin-bottom: 0;
}
.rel-note {
color: #777;
font-size: .9em;
margin-top: .1em;
}
.logo-braces {
color: #df0019;
position: relative;
top: -4px;
}
.blk {
float: left;
}
.left {
width: 37em;
padding-right: 6.53em;
padding-bottom: 1em;
}
.left1 {
width: 15.24em;
padding-right: 6.45em;
}
.left2 {
width: 15.24em;
}
.right {
width: 20.68em;
}
.leftbig {
width: 42.44em;
padding-right: 6.53em;
}
.rightsmall {
width: 15.24em;
}
.clear:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
.clear { display: inline-block; }
/* start commented backslash hack \*/
* html .clear { height: 1%; }
.clear { display: block; }
/* close commented backslash hack */

18
js/codemirror/css/font.js Normal file
View File

@ -0,0 +1,18 @@
function waitForStyles() {
for (var i = 0; i < document.styleSheets.length; i++)
if (/googleapis/.test(document.styleSheets[i].href))
return document.body.className += " droid";
setTimeout(waitForStyles, 100);
}
document.body.style.display = "none";
setTimeout(function() {
document.body.style.display = "";
if (/AppleWebKit/.test(navigator.userAgent) && /iP[oa]d|iPhone/.test(navigator.userAgent)) return;
var link = document.createElement("LINK");
link.type = "text/css";
link.rel = "stylesheet";
link.href = "http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold";
document.documentElement.getElementsByTagName("HEAD")[0].appendChild(link);
waitForStyles();
}, 30);

71
js/codemirror/demo/activeline.html vendored Normal file
View File

@ -0,0 +1,71 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Active Line Demo</title>
<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<link rel="stylesheet" href="../mode/xml/xml.css">
<script src="../mode/xml/xml.js"></script>
<link rel="stylesheet" href="../css/docs.css">
<style type="text/css">
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
.activeline {background: #f0fcff !important;}
</style>
</head>
<body>
<h1>CodeMirror 2: Active Line Demo</h1>
<form><textarea id="code" name="code">
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
xmlns:georss="http://www.georss.org/georss"
xmlns:twitter="http://api.twitter.com">
<channel>
<title>Twitter / codemirror</title>
<link>http://twitter.com/codemirror</link>
<atom:link type="application/rss+xml"
href="http://twitter.com/statuses/user_timeline/242283288.rss" rel="self"/>
<description>Twitter updates from CodeMirror / codemirror.</description>
<language>en-us</language>
<ttl>40</ttl>
<item>
<title>codemirror: http://cloud-ide.com &#8212; they're springing up like mushrooms. This one
uses CodeMirror as its editor.</title>
<description>codemirror: http://cloud-ide.com &#8212; they're springing up like mushrooms. This
one uses CodeMirror as its editor.</description>
<pubDate>Thu, 17 Mar 2011 23:34:47 +0000</pubDate>
<guid>http://twitter.com/codemirror/statuses/48527733722058752</guid>
<link>http://twitter.com/codemirror/statuses/48527733722058752</link>
<twitter:source>web</twitter:source>
<twitter:place/>
</item>
<item>
<title>codemirror: Posted a description of the CodeMirror 2 internals at
http://codemirror.net/2/internals.html</title>
<description>codemirror: Posted a description of the CodeMirror 2 internals at
http://codemirror.net/2/internals.html</description>
<pubDate>Wed, 02 Mar 2011 12:15:09 +0000</pubDate>
<guid>http://twitter.com/codemirror/statuses/42920879788789760</guid>
<link>http://twitter.com/codemirror/statuses/42920879788789760</link>
<twitter:source>web</twitter:source>
<twitter:place/>
</item>
</feed></textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: "application/xml",
lineNumbers: true,
onCursorActivity: function() {
editor.setLineClass(hlLine, null);
hlLine = editor.setLineClass(editor.getCursor().line, "activeline");
}
});
var hlLine = editor.setLineClass(0, "activeline");
</script>
<p>Styling the current cursor line.</p>
</body>
</html>

79
js/codemirror/demo/complete.html vendored Normal file
View File

@ -0,0 +1,79 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Autocomplete Demo</title>
<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<link rel="stylesheet" href="../mode/javascript/javascript.css">
<script src="../mode/javascript/javascript.js"></script>
<link rel="stylesheet" href="../css/docs.css">
<style type="text/css">
.completions {
position: absolute;
z-index: 10;
overflow: hidden;
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
}
.completions select {
background: #fafafa;
outline: none;
border: none;
padding: 0;
margin: 0;
font-family: monospace;
}
.CodeMirror {
border: 1px solid #eee;
}
</style>
</head>
<body>
<h1>CodeMirror 2: Autocomplete demo</h1>
<form><textarea id="code" name="code">
function getCompletions(token, context) {
var found = [], start = token.string;
function maybeAdd(str) {
if (str.indexOf(start) == 0) found.push(str);
}
function gatherCompletions(obj) {
if (typeof obj == "string") forEach(stringProps, maybeAdd);
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
for (var name in obj) maybeAdd(name);
}
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 == "js-variable")
base = window[obj.string];
else if (obj.className == "js-string")
base = "";
else if (obj.className == "js-atom")
base = 1;
while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
}
else {
// If not, just look in the window object and any local scope
// (reading into JS mode internals to get at the local variables)
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
gatherCompletions(window);
forEach(keywords, maybeAdd);
}
return found;
}
</textarea></form>
<p>Press <strong>ctrl-space</strong> to activate autocompletion. See
the <a href="complete.js">code</a> to figure out how it works.</p>
<script src="complete.js"></script>
</body>
</html>

150
js/codemirror/demo/complete.js vendored Normal file
View File

@ -0,0 +1,150 @@
(function () {
// Minimal event-handling wrapper.
function stopEvent() {
if (this.preventDefault) {this.preventDefault(); this.stopPropagation();}
else {this.returnValue = false; this.cancelBubble = true;}
}
function addStop(event) {
if (!event.stop) event.stop = stopEvent;
return event;
}
function connect(node, type, handler) {
function wrapHandler(event) {handler(addStop(event || window.event));}
if (typeof node.addEventListener == "function")
node.addEventListener(type, wrapHandler, false);
else
node.attachEvent("on" + type, wrapHandler);
}
function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
}
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
onKeyEvent: function(i, e) {
// Hook into ctrl-space
if (e.keyCode == 32 && (e.ctrlKey || e.metaKey) && !e.altKey) {
e.stop();
return startComplete();
}
}
});
function startComplete() {
// We want a single cursor position.
if (editor.somethingSelected()) return;
// Find the token at the cursor
var cur = editor.getCursor(false), token = editor.getTokenAt(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 == "." ? "js-property" : null};
}
// If it is a property, find out what it is a property of.
while (tprop.className == "js-property") {
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
if (tprop.string != ".") return;
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
if (!context) var context = [];
context.push(tprop);
}
var completions = getCompletions(token, context);
if (!completions.length) return;
function insert(str) {
editor.replaceRange(str, {line: cur.line, ch: token.start}, {line: cur.line, ch: token.end});
}
// When there is only one completion, use it directly.
if (completions.length == 1) {insert(completions[0]); return true;}
// Build the select widget
var complete = document.createElement("div");
complete.className = "completions";
var sel = complete.appendChild(document.createElement("select"));
sel.multiple = true;
for (var i = 0; i < completions.length; ++i) {
var opt = sel.appendChild(document.createElement("option"));
opt.appendChild(document.createTextNode(completions[i]));
}
sel.firstChild.selected = true;
sel.size = Math.min(10, completions.length);
var pos = editor.cursorCoords();
complete.style.left = pos.x + "px";
complete.style.top = pos.yBot + "px";
document.body.appendChild(complete);
// Hack to hide the scrollbar.
if (completions.length <= 10)
complete.style.width = (sel.clientWidth - 1) + "px";
var done = false;
function close() {
if (done) return;
done = true;
complete.parentNode.removeChild(complete);
}
function pick() {
insert(sel.options[sel.selectedIndex].value);
close();
setTimeout(function(){editor.focus();}, 50);
}
connect(sel, "blur", close);
connect(sel, "keydown", function(event) {
var code = event.keyCode;
// Enter and space
if (code == 13 || code == 32) {event.stop(); pick();}
// Escape
else if (code == 27) {event.stop(); close(); editor.focus();}
else if (code != 38 && code != 40) {close(); editor.focus(); setTimeout(startComplete, 50);}
});
connect(sel, "dblclick", pick);
sel.focus();
// Opera sometimes ignores focusing a freshly created node
if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
return true;
}
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
"toUpperCase toLowerCase split concat match replace search").split(" ");
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
var funcProps = "prototype apply call bind".split(" ");
var keywords = ("break case catch continue debugger default delete do else false finally for function " +
"if in instanceof new null return switch throw true try typeof var void while with").split(" ");
function getCompletions(token, context) {
var found = [], start = token.string;
function maybeAdd(str) {
if (str.indexOf(start) == 0) found.push(str);
}
function gatherCompletions(obj) {
if (typeof obj == "string") forEach(stringProps, maybeAdd);
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
for (var name in obj) maybeAdd(name);
}
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 == "js-variable")
base = window[obj.string];
else if (obj.className == "js-string")
base = "";
else if (obj.className == "js-atom")
base = 1;
while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
}
else {
// If not, just look in the window object and any local scope
// (reading into JS mode internals to get at the local variables)
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
gatherCompletions(window);
forEach(keywords, maybeAdd);
}
return found;
}
})();

53
js/codemirror/demo/marker.html vendored Normal file
View File

@ -0,0 +1,53 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Breakpoint Demo</title>
<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<link rel="stylesheet" href="../mode/javascript/javascript.css">
<script src="../mode/javascript/javascript.js"></script>
<link rel="stylesheet" href="../css/docs.css">
<style type="text/css">
.CodeMirror-gutter {
width: 3em;
background: white;
}
.CodeMirror {
border: 1px solid #aaa;
}
</style>
</head>
<body>
<h1>CodeMirror 2: Breakpoint demo</h1>
<form><textarea id="code" name="code">
CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
onGutterClick: function(cm, n) {
var info = cm.lineInfo(n);
if (info.markerText)
cm.clearMarker(n);
else
cm.setMarker(n, "<span style=\"color: #900\"></span> %N%");
}
});
</textarea></form>
<p>Click the line-number gutter to add or remove 'breakpoints'.</p>
<script>
CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
onGutterClick: function(cm, n) {
var info = cm.lineInfo(n);
if (info.markerText)
cm.clearMarker(n);
else
cm.setMarker(n, "<span style=\"color: #900\"></span> %N%");
}
});
</script>
</body>
</html>

57
js/codemirror/demo/mustache.html vendored Normal file
View File

@ -0,0 +1,57 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Overlay Parser Demo</title>
<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<script src="../lib/overlay.js"></script>
<link rel="stylesheet" href="../mode/xml/xml.css">
<script src="../mode/xml/xml.js"></script>
<link rel="stylesheet" href="../css/docs.css">
<style type="text/css">
.CodeMirror {border: 1px solid black;}
.mustache {color: #0ca;}
</style>
</head>
<body>
<h1>CodeMirror 2: Overlay Parser Demo</h1>
<form><textarea id="code" name="code">
<html>
<body>
<h1>{{title}}</h1>
<p>These are links to {{things}}:</p>
<ul>{{#links}}
<li><a href="{{url}}">{{text}}</a></li>
{{/links}}</ul>
</body>
</html>
</textarea></form>
<script>
CodeMirror.defineMode("mustache", function(config, parserConfig) {
var mustacheOverlay = {
token: function(stream, state) {
if (stream.match("{{")) {
while ((ch = stream.next()) != null)
if (ch == "}" && stream.next() == "}") break;
return "mustache";
}
while (stream.next() != null && !stream.match("{{", false)) {}
return null;
}
};
return CodeMirror.overlayParser(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay);
});
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "mustache"});
</script>
<p>Demonstration of a mode that parses HTML, highlighting
the <a href="http://mustache.github.com/">Mustache</a> templating
directives inside of it by using the code
in <a href="../lib/overlay.js"><code>overlay.js</code></a>. View
source to see the 15 lines of code needed to accomplish this.</p>
</body>
</html>

38
js/codemirror/demo/resize.html vendored Normal file
View File

@ -0,0 +1,38 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Autoresize Demo</title>
<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<link rel="stylesheet" href="../mode/css/css.css">
<script src="../mode/css/css.js"></script>
<link rel="stylesheet" href="../css/docs.css">
<style type="text/css">
.CodeMirror {
border: 1px solid #eee;
height: auto;
}
</style>
</head>
<body>
<h1>CodeMirror 2: Autoresize demo</h1>
<form><textarea id="code" name="code">
.CodeMirror {
height: auto;
}</textarea></form>
<p>By setting a single CSS property, CodeMirror can be made to
automatically resize to fit the content. Use <code>max-height</code>
to prevent it from growing past a given point (on halfway modern
browsers).</p>
<script>
CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true
});
</script>
</body>
</html>

106
js/codemirror/demo/search.html vendored Normal file
View File

@ -0,0 +1,106 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Search/Replace Demo</title>
<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<link rel="stylesheet" href="../mode/xml/xml.css">
<script src="../mode/xml/xml.js"></script>
<link rel="stylesheet" href="../css/docs.css">
<style type="text/css">
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
.searched {background: yellow;}
</style>
</head>
<body>
<h1>CodeMirror 2: Search/Replace Demo</h1>
<form><textarea id="code" name="code">
<dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
<dd>Whether, when indenting, the first N*8 spaces should be
replaced by N tabs. Default is false.</dd>
<dt id="option_tabMode"><code>tabMode (string)</code></dt>
<dd>Determines what happens when the user presses the tab key.
Must be one of the following:
<dl>
<dt><code>"classic" (the default)</code></dt>
<dd>When nothing is selected, insert a tab. Otherwise,
behave like the <code>"shift"</code> mode. (When shift is
held, this behaves like the <code>"indent"</code> mode.)</dd>
<dt><code>"shift"</code></dt>
<dd>Indent all selected lines by
one <a href="#option_indentUnit"><code>indentUnit</code></a>.
If shift was held while pressing tab, un-indent all selected
lines one unit.</dd>
<dt><code>"indent"</code></dt>
<dd>Indent the line the 'correctly', based on its syntactic
context. Only works if the
mode <a href="#indent">supports</a> it.</dd>
<dt><code>"default"</code></dt>
<dd>Do not capture tab presses, let the browser apply its
default behaviour (which usually means it skips to the next
control).</dd>
</dl></dd>
<dt id="option_enterMode"><code>enterMode (string)</code></dt>
<dd>Determines whether and how new lines are indented when the
enter key is pressed. The following modes are supported:
<dl>
<dt><code>"indent" (the default)</code></dt>
<dd>Use the mode's indentation rules to give the new line
the correct indentation.</dd>
<dt><code>"keep"</code></dt>
<dd>Indent the line the same as the previous line.</dd>
<dt><code>"flat"</code></dt>
<dd>Do not indent the new line.</dd>
</dl></dd>
</textarea></form>
<button type=button onclick="search()">Search</button>
<input type=text style="width: 5em" id=query value=indent> or
<button type=button onclick="replace()">replace</button> it by
<input type=text style="width: 5em" id=replace>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", lineNumbers: true});
var lastPos = null, lastQuery = null, marked = [];
function unmark() {
for (var i = 0; i < marked.length; ++i) marked[i]();
marked.length = 0;
}
function search() {
unmark();
var text = document.getElementById("query").value;
if (!text) return;
for (var cursor = editor.getSearchCursor(text); cursor.findNext();)
marked.push(editor.markText(cursor.from(), cursor.to(), "searched"));
if (lastQuery != text) lastPos = null;
var cursor = editor.getSearchCursor(text, lastPos || editor.getCursor());
if (!cursor.findNext()) {
cursor = editor.getSearchCursor(text);
if (!cursor.findNext()) return;
}
editor.setSelection(cursor.from(), cursor.to());
lastQuery = text; lastPos = cursor.to();
}
function replace() {
unmark();
var text = document.getElementById("query").value,
replace = document.getElementById("replace").value;
if (!text) return;
for (var cursor = editor.getSearchCursor(text); cursor.findNext();)
editor.replaceRange(replace, cursor.from(), cursor.to());
}
</script>
<p>Demonstration of search/replace functionality and marking
text.</p>
</body>
</html>

224
js/codemirror/index.html Normal file
View File

@ -0,0 +1,224 @@
<!doctype html>
<html>
<head>
<title>CodeMirror</title>
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel="alternate" href="http://twitter.com/statuses/user_timeline/242283288.rss" type="application/rss+xml"/>
</head>
<body>
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
<pre class="grey">
<img src="css/baboon.png" class="logo" alt="logo"/>/* In-browser code editing
made bearable */
</pre>
<div class="clear"><div class="left blk">
<p style="margin-top: 0">CodeMirror is a JavaScript library that can
be used to create a relatively pleasant editor interface for
code-like content &#x2015; computer programs, HTML markup, and
similar. If a mode has been written for the language you are
editing, the code will be coloured, and the editor will optionally
help you with indentation.</p>
<p>This is the project page for CodeMirror 2, the currently more
actively developed, and recommended
version. <a href="1/index.html">CodeMirror 1</a> is still available
from here.</p>
<div class="clear"><div class="left1 blk">
<h2 style="margin-top: 0">Supported modes:</h2>
<ul>
<li><a href="mode/javascript/index.html">JavaScript</a></li>
<li><a href="mode/xml/index.html">XML/HTML</a></li>
<li><a href="mode/css/index.html">CSS</a></li>
<li><a href="mode/htmlmixed/index.html">HTML mixed-mode</a></li>
<li><a href="mode/python/index.html">Python</a></li>
<li><a href="mode/php/index.html">PHP</a></li>
<li><a href="mode/diff/index.html">diff</a></li>
<li><a href="mode/clike/index.html">C, Java, and similar</a></li>
<li><a href="mode/stex/index.html">sTeX, LaTeX</a></li>
<li><a href="mode/haskell/index.html">Haskell</a></li>
<li><a href="mode/smalltalk/index.html">Smalltalk</a></li>
<li><a href="mode/rst/index.html">reStructuredText</a></li>
<li><a href="mode/plsql/index.html">PL/SQL</a></li>
</ul>
</div><div class="left2 blk">
<h2 style="margin-top: 0">Usage demos:</h2>
<ul>
<li><a href="demo/complete.html">Autocompletion</a></li>
<li><a href="demo/mustache.html">Mode overlays</a></li>
<li><a href="demo/search.html">Search/replace</a></li>
<li><a href="demo/resize.html">Auto-resizing editor</a></li>
<li><a href="demo/marker.html">Setting breakpoints</a></li>
<li><a href="demo/activeline.html">Highlighting the current line</a></li>
</ul>
</div></div>
<h2 id="code">Getting the code</h2>
<p>All of CodeMirror is released under a <a
href="LICENSE">MIT-style</a> license. To get it, you can download
the <a href="http://codemirror.net/codemirror.zip">latest
release</a> or the current <a
href="http://codemirror.net/codemirror2-latest.zip">development
snapshot</a> as zip files. To create a custom minified script file,
you can use the <a href="compress.html">compression API</a>.</p>
<p>We use <a href="http://git-scm.com/">git</a> for version control.
The main repository can be fetched in this way:</p>
<pre class="code">git clone http://marijnhaverbeke.nl/git/codemirror2</pre>
<p>CodeMirror can also be found on GitHub at <a
href="http://github.com/marijnh/CodeMirror2">marijnh/CodeMirror2</a>.
If you plan to hack on the code and contribute patches, the best way
to do it is to create a GitHub fork, and send pull requests.</p>
<h2 id="documention">Documentation</h2>
<p>The <a href="manual.html">manual</a> is your first stop for
learning how to use this library. It starts with a quick explanation
of how to use the editor, and then describes all of the (many)
options and methods that CodeMirror exposes.</p>
<p>For those who want to learn more about the code, there is
an <a href="internals.html">overview of the internals</a> available.
The <a href="http://github.com/marijnh/CodeMirror2">source code</a>
itself is, for the most part, also well commented.</p>
<h2 id="support">Support and bug reports</h2>
<p>There is
a <a href="http://groups.google.com/group/codemirror">Google
group</a> (a sort of mailing list/newsgroup thing) for discussion
and news related to CodeMirror. Reporting bugs is best done
on <a href="http://github.com/marijnh/CodeMirror2/issues">github</a>.
You can also e-mail me
directly: <a href="mailto:marijnh@gmail.com">Marijn
Haverbeke</a>.</p>
<h2 id="supported">Supported browsers</h2>
<p>The following browsers are able to run CodeMirror:</p>
<ul>
<li>Firefox 2 or higher</li>
<li>Chrome, any version</li>
<li>Safari 3 or higher</li>
<li>Internet Explorer 6 or higher</li>
<li>Opera 9 or higher (with some key-handling problems on OS X)</li>
</ul>
<p>I am not actively testing against every new browser release, and
vendors have a habit of introducing bugs all the time, so I am
relying on the community to tell me when something breaks.
See <a href="#support">here</a> for information on how to contact
me.</p>
</div>
<div class="right blk">
<a href="http://codemirror.net/codemirror.zip" class="download">Download the latest release</a>
<h2>Make a donation</h2>
<ul>
<li><span onclick="document.getElementById('paypal').submit();" class="quasilink">Paypal</span></li>
<li><span onclick="document.getElementById('bankinfo').style.display = 'block';" class="quasilink">Bank</span></li>
</ul>
<p id="bankinfo" style="display: none;">
Bank: <i>Rabobank</i><br/>
Country: <i>Netherlands</i><br/>
SWIFT: <i>RABONL2U</i><br/>
Account: <i>147850770</i><br/>
Name: <i>Marijn Haverbeke</i><br/>
IBAN: <i>NL26 RABO 0147 8507 70</i>
</p>
<h2>Releases:</h2>
<p class="rel">26-05-2011: <a href="http://codemirror.net/codemirror-2.01.zip">Version 2.01</a>:</p>
<ul class="rel-note">
<li>Add a <a href="mode/smalltalk/index.html">Smalltalk mode</a>.</li>
<li>Add a <a href="mode/rst/index.html">reStructuredText mode</a>.</li>
<li>Add a <a href="mode/python/index.html">Python mode</a>.</li>
<li>Add a <a href="mode/plsql/index.html">PL/SQL mode</a>.</li>
<li><code>coordsChar</code> now works</li>
<li>Fix a problem where <code>onCursorActivity</code> interfered with <code>onChange</code>.</li>
<li>Fix a number of scrolling and mouse-click-position glitches.</li>
<li>Pass information about the changed lines to <code>onChange</code>.</li>
<li>Support cmd-up/down on OS X.</li>
<li>Add triple-click line selection.</li>
<li>Don't handle shift when changing the selection through the API.</li>
<li>Support <code>"nocursor"</code> mode for <code>readOnly</code> option.</li>
<li>Add an <code>onHighlightComplete</code> option.</li>
<li>Fix the context menu for Firefox.</li>
</ul>
<p class="rel">28-03-2011: <a href="http://codemirror.net/codemirror-2.0.zip">Version 2.0</a>:</p>
<p class="rel-note">CodeMirror 2 is a complete rewrite that's
faster, smaller, simpler to use, and less dependent on browser
quirks. See <a href="internals.html">this</a>
and <a href="http://groups.google.com/group/codemirror/browse_thread/thread/5a8e894024a9f580">this</a>
for more information.</a>
<p class="rel">28-03-2011: <a href="http://codemirror.net/codemirror-1.0.zip">Version 1.0</a>:</p>
<ul class="rel-note">
<li>Fix error when debug history overflows.</li>
<li>Refine handling of C# verbatim strings.</li>
<li>Fix some issues with JavaScript indentation.</li>
</ul>
<p class="rel">22-02-2011: <a href="https://github.com/marijnh/codemirror2/tree/beta2">Version 2.0 beta 2</a>:</p>
<p class="rel-note">Somewhate more mature API, lots of bugs shaken out.</a>
<p class="rel">17-02-2011: <a href="http://codemirror.net/codemirror-0.94.zip">Version 0.94</a>:</p>
<ul class="rel-note">
<li><code>tabMode: "spaces"</code> was modified slightly (now indents when something is selected).</li>
<li>Fixes a bug that would cause the selection code to break on some IE versions.</li>
<li>Disabling spell-check on WebKit browsers now works.</li>
</ul>
<p class="rel">08-02-2011: <a href="http://codemirror.net/2/">Version 2.0 beta 1</a>:</p>
<p class="rel-note">CodeMirror 2 is a complete rewrite of
CodeMirror, no longer depending on an editable frame.</p>
<p class="rel">19-01-2011: <a href="http://codemirror.net/codemirror-0.93.zip">Version 0.93</a>:</p>
<ul class="rel-note">
<li>Added a <a href="contrib/regex/index.html">Regular Expression</a> parser.</li>
<li>Fixes to the PHP parser.</li>
<li>Support for regular expression in search/replace.</li>
<li>Add <code>save</code> method to instances created with <code>fromTextArea</code>.</li>
<li>Add support for MS T-SQL in the SQL parser.</li>
<li>Support use of CSS classes for highlighting brackets.</li>
<li>Fix yet another hang with line-numbering in hidden editors.</li>
</ul>
<p><a href="oldrelease.html">Older releases...</a></p>
</div></div>
<div style="height: 2em">&nbsp;</div>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" id="paypal">
<input type="hidden" name="cmd" value="_s-xclick"/>
<input type="hidden" name="hosted_button_id" value="3FVHS5FGUY7CC"/>
</form>
<script type="text/javascript" src="css/font.js"></script>
</body>
</html>

View File

@ -0,0 +1,382 @@
<!doctype html>
<html>
<head>
<title>CodeMirror: Internals</title>
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style>dl dl {margin: 0;}</style>
</head>
<body>
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
<pre class="grey">
<img src="css/baboon.png" class="logo" alt="logo"/>/* (Re-) Implementing A Syntax-
Highlighting Editor in JavaScript */
</pre>
<div class="clear"><div class="leftbig blk">
<p style="font-size: 85%" id="intro">
<strong>Topic:</strong> JavaScript, code editor implementation<br>
<strong>Author:</strong> Marijn Haverbeke<br>
<strong>Date:</strong> March 2nd 2011
</p>
<p>This is a followup to
my <a href="http://codemirror.net/story.html">Brutal Odyssey to the
Dark Side of the DOM Tree</a> story. That one describes the
mind-bending process of implementing (what would become) CodeMirror 1.
This one describes the internals of CodeMirror 2, a complete rewrite
and rethink of the old code base. I wanted to give this piece another
Hunter Thompson copycat subtitle, but somehow that would be out of
place—the process this time around was one of straightforward
engineering, requiring no serious mind-bending whatsoever.</p>
<p>So, what is wrong with CodeMirror 1? I'd estimate, by mailing list
activity and general search-engine presence, that it has been
integrated into about a thousand systems by now. The most prominent
one, since a few weeks,
being <a href="http://googlecode.blogspot.com/2011/01/make-quick-fixes-quicker-on-google.html">Google
code's project hosting</a>. It works, and it's being used widely.</a>
<p>Still, I did not start replacing it because I was bored. CodeMirror
1 was heavily reliant on <code>designMode</code>
or <code>contentEditable</code> (depending on the browser). Neither of
these are well specified (HTML5 tries
to <a href="http://www.w3.org/TR/html5/editing.html#contenteditable">specify</a>
their basics), and, more importantly, they tend to be one of the more
obscure and buggy areas of browser functionality—CodeMirror, by using
this functionality in a non-typical way, was constantly running up
against browser bugs. WebKit wouldn't show an empty line at the end of
the document, and in some releases would suddenly get unbearably slow.
Firefox would show the cursor in the wrong place. Internet Explorer
would insist on linkifying everything that looked like a URL or email
address, a behaviour that can't be turned off. Some bugs I managed to
work around (which was often a frustrating, painful process), others,
such as the Firefox cursor placement, I gave up on, and had to tell
user after user that they were known problems, but not something I
could help.</p>
<p>Also, there is the fact that <code>designMode</code> (which seemed
to be less buggy than <code>contentEditable</code> in Webkit and
Firefox, and was thus used by CodeMirror 1 in those browsers) requires
a frame. Frames are another tricky area. It takes some effort to
prevent getting tripped up by domain restrictions, they don't
initialize synchronously, behave strangely in response to the back
button, and, on several browsers, can't be moved around the DOM
without having them re-initialize. They did provide a very nice way to
namespace the library, though—CodeMirror 1 could freely pollute the
namespace inside the frame.</p>
<p>Finally, working with an editable document means working with
selection in arbitrary DOM structures. Internet Explorer (8 and
before) has an utterly different (and awkward) selection API than all
of the other browsers, and even among the different implementations of
<code>document.selection</code>, details about how exactly a selection
is represented vary quite a bit. Add to that the fact that Opera's
selection support tended to be very buggy until recently, and you can
imagine why CodeMirror 1 contains 700 lines of selection-handling
code.</p>
<p>And that brings us to the main issue with the CodeMirror 1
code base: The proportion of browser-bug-workarounds to real
application code was getting dangerously high. By building on top of a
few dodgy features, I put the system in a vulnerable position—any
incompatibility and bugginess in these features, I had to paper over
with my own code. Not only did I have to do some serious stunt-work to
get it to work on older browsers (as detailed in the
previous <a href="http://codemirror.net/story.html">story</a>), things
also kept breaking in newly released versions, requiring me to come up
with <em>new</em> scary hacks in order to keep up. This was starting
to lose its appeal.</p>
<h2 id="approach">General Approach</h2>
<p>What CodeMirror 2 does is try to sidestep most of the hairy hacks
that came up in version 1. I owe a lot to the
<a href="http://ace.ajax.org">ACE</a> editor for inspiration on how to
approach this.</p>
<p>I absolutely did not want to be completely reliant on key events to
generate my input. Every JavaScript programmer knows that key event
information is horrible and incomplete. Some people (most awesomely
Mihai Bazon with <a href="http://ymacs.org">Ymacs</a>) have been able
to build more or less functioning editors by directly reading key
events, but it takes a lot of work (the kind of never-ending, fragile
work I described earlier), and will never be able to properly support
things like multi-keystoke international character input.</p>
<p>So what I do is focus a hidden textarea, and let the browser
believe that the user is typing into that. What we show to the user is
a DOM structure we built to represent his document. If this is updated
quickly enough, and shows some kind of believable cursor, it feels
like a real text-input control.</p>
<p>Another big win is that this DOM representation does not have to
span the whole document. Some CodeMirror 1 users insisted that they
needed to put a 30 thousand line XML document into CodeMirror. Putting
all that into the DOM takes a while, especially since, for some
reason, an editable DOM tree is slower than a normal one on most
browsers. If we have full control over what we show, we must only
ensure that the visible part of the document has been added, and can
do the rest only when needed. (Fortunately, the <code>onscroll</code>
event works almost the same on all browsers, and lends itself well to
displaying things only as they are scrolled into view.)</p>
<h2 id="input">Input</h2>
<p>ACE uses its hidden textarea only as a text input shim, and does
all cursor movement and things like text deletion itself by directly
handling key events. CodeMirror's way is to let the browser do its
thing as much as possible, and not, for example, define its own set of
key bindings. One way to do this would have been to have the whole
document inside the hidden textarea, and after each key event update
the display DOM to reflect what's in that textarea.</p>
<p>That'd be simple, but it is not realistic. For even medium-sized
document the editor would be constantly munging huge strings, and get
terribly slow. What CodeMirror 2 does is put the current selection,
along with an extra line on the top and on the bottom, into the
textarea.</p>
<p>This means that the arrow keys (and their ctrl-variations), home,
end, etcetera, do not have to be handled specially. We just read the
cursor position in the textarea, and update our cursor to match it.
Also, copy and paste work pretty much for free, and people get their
native key bindings, without any special work on my part. For example,
I have emacs key bindings configured for Chrome and Firefox. There is
no way for a script to detect this.</p>
<p>Of course, since only a small part of the document sits in the
textarea, keys like page up and ctrl-end won't do the right thing.
CodeMirror is catching those events and handling them itself.</p>
<h2 id="selection">Selection</h2>
<p>Getting and setting the selection range of a textarea in modern
browsers is trivial—you just use the <code>selectionStart</code>
and <code>selectionEnd</code> properties. On IE you have to do some
insane stuff with temporary ranges and compensating for the fact that
moving the selection by a 'character' will treat \r\n as a single
character, but even there it is possible to build functions that
reliably set and get the selection range.</p>
<p>But consider this typical case: When I'm somewhere in my document,
press shift, and press the up arrow, something gets selected. Then, if
I, still holding shift, press the up arrow again, the top of my
selection is adjusted. The selection remembers where its <em>head</em>
and its <em>anchor</em> are, and moves the head when we shift-move.
This is a generally accepted property of selections, and done right by
every editing component built in the past twenty years.</p>
<p>But not something that the browser selection APIs expose.</p>
<p>Great. So when someone creates an 'upside-down' selection, the next
time CodeMirror has to update the textarea, it'll re-create the
selection as an 'upside-up' selection, with the anchor at the top, and
the next cursor motion will behave in an unexpected way—our second
up-arrow press in the example above will not do anything, since it is
interpreted in exactly the same way as the first.</p>
<p>No problem. We'll just, ehm, detect that the selection is
upside-down (you can tell by the way it was created), and then, when
an upside-down selection is present, and a cursor-moving key is
pressed in combination with shift, we quickly collapse the selection
in the textarea to its start, allow the key to take effect, and then
combine its new head with its old anchor to get the <em>real</em>
selection.</p>
<p>In short, scary hacks could not be avoided entirely in CodeMirror
2.</p>
<p>And, the observant reader might ask, how do you even know that a
key combo is a cursor-moving combo, if you claim you support any
native key bindings? Well, we don't, but we can learn. The editor
keeps a set known cursor-movement combos (initialized to the
predictable defaults), and updates this set when it observes that
pressing a certain key had (only) the effect of moving the cursor.
This, of course, doesn't work if the first time the key is used was
for extending an inverted selection, but it works most of the
time.</p>
<h2 id="update">Intelligent Updating</h2>
<p>One thing that always comes up when you have a complicated internal
state that's reflected in some user-visible external representation
(in this case, the displayed code and the textarea's content) is
keeping the two in sync. The naive way is to just update the display
every time you change your state, but this is not only error prone
(you'll forget), it also easily leads to duplicate work on big,
composite operations. Then you start passing around flags indicating
whether the display should be updated in an attempt to be efficient
again and, well, at that point you might as well give up completely.</p>
<p>I did go down that road, but then switched to a much simpler model:
simply keep track of all the things that have been changed during an
action, and then, only at the end, use this information to update the
user-visible display.</p>
<p>CodeMirror uses a concept of <em>operations</em>, which start by
calling a specific set-up function that clears the state and end by
calling another function that reads this state and does the required
updating. Most event handlers, and all the user-visible methods that
change state are wrapped like this. There's a method
called <code>operation</code> that accepts a function, and returns
another function that wraps the given function as an operation.</p>
<p>It's trivial to extend this (as CodeMirror does) to detect nesting,
and, when an operation is started inside an operation, simply
increment the nesting count, and only do the updating when this count
reaches zero again.</p>
<p>If we have a set of changed ranges and know the currently shown
range, we can (with some awkward code to deal with the fact that
changes can add and remove lines, so we're dealing with a changing
coordinate system) construct a map of the ranges that were left
intact. We can then compare this map with the part of the document
that's currently visible (based on scroll offset and editor height) to
determine whether something needs to be updated.</p>
<p>CodeMirror uses two update algorithms—a full refresh, where it just
discards the whole part of the DOM that contains the edited text and
rebuilds it, and a patch algorithm, where it uses the information
about changed and intact ranges to update only the out-of-date parts
of the DOM. When more than 30 percent (which is the current heuristic,
might change) of the lines need to be updated, the full refresh is
chosen (since it's faster to do than painstakingly finding and
updating all the changed lines), in the other case it does the
patching (so that, if you scroll a line or select another character,
the whole screen doesn't have to be re-rendered).</p>
<p>All updating uses <code>innerHTML</code> rather than direct DOM
manipulation, since that still seems to be by far the fastest way to
build documents. There's a per-line function that combines the
highlighting, <a href="manual.html#markText">marking</a>, and
selection info for that line into a snippet of HTML. The patch updater
uses this to reset individual lines, the refresh updater builds an
HTML chunk for the whole visible document at once, and then uses a
single <code>innerHTML</code> update to do the refresh.</p>
<h2 id="parse">Parsers can be Simple</h2>
<p>When I wrote CodeMirror 1, I
thought <a href="http://codemirror.net/story.html#parser">interruptable
parsers</a> were a hugely scary and complicated thing, and I used a
bunch of heavyweight abstractions to keep this supposed complexity
under control: parsers
were <a href="http://bob.pythonmac.org/archives/2005/07/06/iteration-in-javascript/">iterators</a>
that consumed input from another iterator, and used funny
closure-resetting tricks to copy and resume themselves.</p>
<p>This made for a rather nice system, in that parsers formed strictly
separate modules, and could be composed in predictable ways.
Unfortunately, it was quite slow (stacking three or four iterators on
top of each other), and extremely intimidating to people not used to a
functional programming style.</p>
<p>With a few small changes, however, we can keep all those
advantages, but simplify the API and make the whole thing less
indirect and inefficient. CodeMirror
2's <a href="manual.html#modeapi">mode API</a> uses explicit state
objects, and makes the parser/tokenizer a function that simply takes a
state and a character stream abstraction, advances the stream one
token, and returns the way the token should be styled. This state may
be copied, optionally in a mode-defined way, in order to be able to
continue a parse at a given point. Even someone who's never touched a
lambda in his life can understand this approach. Additionally, far
fewer objects are allocated in the course of parsing now.</p>
<p>The biggest speedup comes from the fact that the parsing no longer
has to touch the DOM though. In CodeMirror 1, on an older browser, you
could <em>see</em> the parser work its way through the document,
managing some twenty lines in each 50-millisecond time slice it got. It
was reading its input from the DOM, and updating the DOM as it went
along, which any experienced JavaScript programmer will immediately
spot as a recipe for slowness. In CodeMirror 2, the parser usually
finishes the whole document in a single 100-millisecond time slice—it
manages some 1500 lines during that time on Chrome. All it has to do
is munge strings, so there is no real reason for it to be slow
anymore.</p>
<h2 id="summary">What Gives?</h2>
<p>Given all this, what can you expect from CodeMirror 2? First, the
good:</p>
<ul>
<li><strong>Small.</strong> the base library is some 32k when minified
now, 12k when gzipped. It's smaller than its own logo.</li>
<li><strong>Lightweight.</strong> CodeMirror 2 initializes very
quickly, and does almost no work when it is not focused. This means
you can treat it almost like a textarea, have multiple instances on a
page without trouble.</li>
<li><strong>Huge document support.</strong> Since highlighting is
really fast, and no DOM structure is being built for non-visible
content, you don't have to worry about locking up your browser when a
user enters a megabyte-sized document.</li>
<li><strong>Extended API.</strong> Some things kept coming up in the
mailing list, such as marking pieces of text or lines, which were
extremely hard to do with CodeMirror 1. The new version has proper
support for these built in.</li>
<li><strong>Tab support.</strong> Tabs inside editable documents were,
for some reason, a no-go. At least six different people announced they
were going to add tab support to CodeMirror 1, none survived (I mean,
none delivered a working version). CodeMirror 2 no longer removes tabs
from your document.</li>
<li><strong>Sane styling.</strong> <code>iframe</code> nodes aren't
really known for respecting document flow. Now that an editor instance
is a plain <code>div</code> element, it is much easier to size it to
fit the surrounding elements. You don't even have to make it scroll if
you do not <a href="demo/resize.html">want to</a>.</li>
</ul>
<p>Then, the bad:</p>
<ul>
<li><strong>No line-wrapping.</strong> I'd have liked to get
line-wrapping to work, but it doesn't match the model I'm using very
well. It is important that cursor movement in the textarea matches
what you see on the screen, and it seems to be impossible to have the
lines wrapped the same in the textarea and the normal DOM.</li>
<li><strong>Some cursor flakiness.</strong> The textarea hack does not
really do justice to the complexity of cursor handling—a selection is
typically more than just an offset into a string. For example, if you
use the up and down arrow keys to move to a shorter line and then
back, you'll end up in your old position in most editor controls, but
CodeMirror 2 currently doesn't remember the 'real' cursor column in
this case. These can be worked around on a case-by-case basis, but
I haven't put much energy into that yet.</li>
</ul>
</div><div class="rightsmall blk">
<h2>Contents</h2>
<ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#approach">General Approach</a></li>
<li><a href="#input">Input</a></li>
<li><a href="#selection">Selection</a></li>
<li><a href="#update">Intelligent Updating</a></li>
<li><a href="#parse">Parsing</a></li>
<li><a href="#summary">What Gives?</a></li>
</ul>
</div></div>
<div style="height: 2em">&nbsp;</div>
<script type="text/javascript" src="css/font.js"></script>
</body></html>

56
js/codemirror/lib/codemirror.css vendored Normal file
View File

@ -0,0 +1,56 @@
.CodeMirror {
overflow: auto;
height: 300px;
line-height: 1em;
font-family: monospace;
}
.CodeMirror-gutter {
position: absolute; left: 0; top: 0;
background-color: #f7f7f7;
border-right: 1px solid #eee;
min-width: 2em;
height: 100%;
}
.CodeMirror-gutter-text {
color: #aaa;
text-align: right;
padding: .4em .2em .4em .4em;
}
.CodeMirror-lines {
padding: .4em;
}
.CodeMirror pre {
-moz-border-radius: 0;
-webkit-border-radius: 0;
-o-border-radius: 0;
border-radius: 0;
border-width: 0; margin: 0; padding: 0; background: transparent;
font-family: inherit;
}
.CodeMirror textarea {
font-family: monospace !important;
}
.CodeMirror-cursor {
z-index: 10;
position: absolute;
visibility: hidden;
border-left: 1px solid black !important;
}
.CodeMirror-focused .CodeMirror-cursor {
visibility: visible;
}
span.CodeMirror-selected {
background: #ccc !important;
color: HighlightText !important;
}
.CodeMirror-focused span.CodeMirror-selected {
background: Highlight !important;
}
.CodeMirror-matchingbracket {color: #0f0 !important;}
.CodeMirror-nonmatchingbracket {color: #f22 !important;}

2018
js/codemirror/lib/codemirror.js vendored Normal file

File diff suppressed because it is too large Load Diff

51
js/codemirror/lib/overlay.js vendored Normal file
View File

@ -0,0 +1,51 @@
// Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true, in which case
// the styles are combined.
CodeMirror.overlayParser = function(base, overlay, combine) {
return {
startState: function() {
return {
base: CodeMirror.startState(base),
overlay: CodeMirror.startState(overlay),
basePos: 0, baseCur: null,
overlayPos: 0, overlayCur: null
};
},
copyState: function(state) {
return {
base: CodeMirror.copyState(base, state.base),
overlay: CodeMirror.copyState(overlay, state.overlay),
basePos: state.basePos, baseCur: null,
overlayPos: state.overlayPos, overlayCur: null
};
},
token: function(stream, state) {
if (stream.start == state.basePos) {
state.baseCur = base.token(stream, state.base);
state.basePos = stream.pos;
}
if (stream.start == state.overlayPos) {
stream.pos = stream.start;
state.overlayCur = overlay.token(stream, state.overlay);
state.overlayPos = stream.pos;
}
stream.pos = Math.min(state.basePos, state.overlayPos);
if (stream.eol()) state.basePos = state.overlayPos = 0;
if (state.overlayCur == null) return state.baseCur;
if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
else return state.overlayCur;
},
indent: function(state, textAfter) {
return base.indent(state.base, textAfter);
},
electricChars: base.electricChars
};
};

797
js/codemirror/manual.html Normal file
View File

@ -0,0 +1,797 @@
<!doctype html>
<html>
<head>
<title>CodeMirror: User Manual</title>
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style>dl dl {margin: 0;}</style>
</head>
<body>
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
<pre class="grey">
<img src="css/baboon.png" class="logo" alt="logo"/>/* User manual and
reference guide */
</pre>
<div class="clear"><div class="leftbig blk">
<h2 id="overview">Overview</h2>
<p>CodeMirror is a code-editor component that can be embedded in
Web pages. It provides <em>only</em> the editor component, no
accompanying buttons
(see <a href="http://www.octolabs.com/javascripts/codemirror-ui/">CodeMirror
UI</a> for a drop-in button bar), auto-completion, or other IDE
functionality. It does provide a rich API on top of which such
functionality can be straightforwardly implemented.</p>
<p>CodeMirror works with language-specific modes. Modes are
JavaScript programs that help color (and optionally indent) text
written in a given language. The distribution comes with a few
modes (see the <code>mode/</code> directory), and it isn't hard
to <a href="#modeapi">write new ones</a> for other languages.</p>
<h2 id="usage">Basic Usage</h2>
<p>The easiest way to use CodeMirror is to simply load the script
and style sheet found under <code>lib/</code> in the distribution,
plus the script and style sheet for the mode(s) you want to use.
(See also <a href="compress.html">the compresion helper</a>.) For
example:</p>
<pre>&lt;script src="lib/codemirror.js">&lt;/script>
&lt;link rel="stylesheet" href="lib/codemirror.css">
&lt;script src="mode/javascript/javascript.js">&lt;/script>
&lt;link rel="stylesheet" href="mode/javascript/javascript.css"></pre>
<p>Having done this, an editor instance can be created like
this:</p>
<pre>var myCodeMirror = CodeMirror(document.body);</pre>
<p>The editor will be appended to the document body, will start
empty, and will use the mode that we loaded. To have more control
over the new editor, a configuration object can be passed
to <code>CodeMirror</code> as a second argument:</p>
<pre>var myCodeMirror = CodeMirror(document.body, {
value: "function myScript(){return 100;}\n",
mode: "javascript"
});</pre>
<p>This will initialize the editor with a piece of code already in
it, and explicitly tell it to use the JavaScript mode (which is
useful when multiple modes are loaded).
See <a href="#config">below</a> for a full discussion of the
configuration options that CodeMirror accepts.</p>
<p>In cases where you don't want to append the editor to an
element, and need more control over the way it is inserted, the
first argument to the <code>CodeMirror</code> function can also
be a function that, when given a DOM element, inserts it into the
document somewhere. This could be used to, for example, replace a
textarea with a real editor:</p>
<pre>var myCodeMirror = CodeMirror(function(elt) {
myTextArea.parentNode.replaceChild(elt, myTextArea);
}, {value: myTextArea.value});</pre>
<p>However, for this use case, which is a common way to use
CodeMirror, the library provides a much more powerful
shortcut:</p>
<pre>var myCodeMirror = CodeMirror.fromTextArea(myTextArea);</pre>
<p>This will, among other things, ensure that the textarea's value
is updated when the form (if it is part of a form) is submitted.
See the <a href="#fromTextArea">API reference</a> for a full
description of this method.</p>
<h2 id="config">Configuration</h2>
<p>Both the <code>CodeMirror</code> function and
its <code>fromTextArea</code> method take as second (optional)
argument an object containing configuration options. Any option
not supplied like this will be taken
from <code>CodeMirror.defaults</code>, an object containing the
default options. You can update this object to change the defaults
on your page.</p>
<p>Options are not checked in any way, so setting bogus option
values is bound to lead to odd errors.</p>
<p><em>Note:</em> CodeMirror
2 <a href="internals.html#summary">does not support</a>
line-wrapping. I would have very much liked to support it, but it
combines extremely poorly with the way the editor is
implemented.</p>
<p>These are the supported options:</p>
<dl>
<dt id="option_value"><code>value (string)</code></dt>
<dd>The starting value of the editor.</dd>
<dt id="option_mode"><code>mode (string or object)</code></dt>
<dd>The mode to use. When not given, this will default to the
first mode that was loaded. It may be a string, which either
simply names the mode or is
a <a href="http://en.wikipedia.org/wiki/MIME">MIME</a> type
associated with the mode. Alternatively, it may be an object
containing configuration options for the mode, with
a <code>name</code> property that names the mode (for
example <code>{name: "javascript", json: true}</code>). The demo
pages for each mode contain information about what configuration
parameters the mode supports. You can ask CodeMirror which modes
and MIME types are loaded with
the <code>CodeMirror.listModes</code>
and <code>CodeMirror.listMIMEs</code> functions.</dd>
<dt id="option_indentUnit"><code>indentUnit (integer)</code></dt>
<dd>How many spaces a block (whatever that means in the edited
language) should be indented. The default is 2.</dd>
<dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
<dd>Whether, when indenting, the first N*8 spaces should be
replaced by N tabs. Default is false.</dd>
<dt id="option_tabMode"><code>tabMode (string)</code></dt>
<dd>Determines what happens when the user presses the tab key.
Must be one of the following:
<dl>
<dt><code>"classic" (the default)</code></dt>
<dd>When nothing is selected, insert a tab. Otherwise,
behave like the <code>"shift"</code> mode. (When shift is
held, this behaves like the <code>"indent"</code> mode.)</dd>
<dt><code>"shift"</code></dt>
<dd>Indent all selected lines by
one <a href="#option_indentUnit"><code>indentUnit</code></a>.
If shift was held while pressing tab, un-indent all selected
lines one unit.</dd>
<dt><code>"indent"</code></dt>
<dd>Indent the line the 'correctly', based on its syntactic
context. Only works if the
mode <a href="#indent">supports</a> it.</dd>
<dt><code>"default"</code></dt>
<dd>Do not capture tab presses, let the browser apply its
default behaviour (which usually means it skips to the next
control).</dd>
</dl></dd>
<dt id="option_enterMode"><code>enterMode (string)</code></dt>
<dd>Determines whether and how new lines are indented when the
enter key is pressed. The following modes are supported:
<dl>
<dt><code>"indent" (the default)</code></dt>
<dd>Use the mode's indentation rules to give the new line
the correct indentation.</dd>
<dt><code>"keep"</code></dt>
<dd>Indent the line the same as the previous line.</dd>
<dt><code>"flat"</code></dt>
<dd>Do not indent the new line.</dd>
</dl></dd>
<dt id="option_electricChars"><code>electricChars (boolean)</code></dt>
<dd>Configures whether the editor should re-indent the current
line when a character is typed that might change its proper
indentation (only works if the mode supports indentation).
Default is true.</dd>
<dt id="option_lineNumbers"><code>lineNumbers (boolean)</code></dt>
<dd>Whether to show line numbers to the left of the editor.</dd>
<dt id="option_firstLineNumber"><code>firstLineNumber (integer)</code></dt>
<dd>At which number to start counting lines. Default is 1.</dd>
<dt id="option_gutter"><code>gutter (boolean)</code></dt>
<dd>Can be used to force a 'gutter' (empty space on the left of
the editor) to be shown even when no line numbers are active.
This is useful for setting <a href="#setMarker">markers</a>.</dd>
<dt id="option_readOnly"><code>readOnly (boolean)</code></dt>
<dd>This disables editing of the editor content by the user.
(Changes through API functions will still be possible.) If you
also want to disable the cursor, use <code>"nocursor"</code> as
a value for this option, instead of <code>true</code>.</dd>
<dt id="option_onChange"><code>onChange (function)</code></dt>
<dd>When given, this function will be called every time the
content of the editor is changed. It will be given the editor
instance as only argument.</dd>
<dt id="option_onCursorActivity"><code>onCursorActivity (function)</code></dt>
<dd>Like <code>onChange</code>, but will also be called when the
cursor moves without any changes being made.</dd>
<dt id="option_onGutterClick"><code>onGutterClick (function)</code></dt>
<dd>When given, will be called whenever the editor gutter (the
line-number area) is clicked. Will be given the editor instance
as first argument, and the (zero-based) number of the line that
was clicked as second argument.</dd>
<dt id="option_onFocus"><code>onFocus, onBlur (function)</code></dt>
<dd>The given functions will be called whenever the editor is
focused or unfocused.</dd>
<dt id="option_onScroll"><code>onScroll (function)</code></dt>
<dd>When given, will be called whenever the editor is
scrolled.</dd>
<dt id="option_onHighlightComplete"><code>onHighlightComplete (function)</code></dt>
<dd>Whenever the editor's content has been fully highlighted,
this function (if given) will be called. It'll be given a single
argument, the editor instance.</dd>
<dt id="option_matchBrackets"><code>matchBrackets (boolean)</code></dt>
<dd>Determines whether brackets are matched whenever the cursor
is moved next to a bracket.</dd>
<dt id="option_workTime"><code>workTime, workDelay (number)</code></dt>
<dd>Highlighting is done by a pseudo background-thread that will
work for <code>workTime</code> milliseconds, and then use
timeout to sleep for <code>workDelay</code> milliseconds. The
defaults are 200 and 300, you can change these options to make
the highlighting more or less aggressive.</dd>
<dt id="option_undoDepth"><code>undoDepth (integer)</code></dt>
<dd>The maximum number of undo levels that the editor stores.
Defaults to 40.</dd>
<dt id="option_tabindex"><code>tabindex (integer)</code></dt>
<dd>The <a href="http://www.w3.org/TR/html401/interact/forms.html#adef-tabindex">tab
index</a> to assign to the editor. If not given, no tab index
will be assigned.</dd>
<dt id="option_document"><code>document (DOM document)</code></dt>
<dd>Use this if you want to display the editor in another DOM.
By default it will use the global <code>document</code>
object.</dd>
<dt id="option_onKeyEvent"><code>onKeyEvent (function)</code></dt>
<dd>This provides a rather low-level hook into CodeMirror's key
handling. If provided, this function will be called on
every <code>keydown</code>, <code>keyup</code>,
and <code>keypress</code> event that CodeMirror captures. It
will be passed two arguments, the editor instance and the key
event. This key event is pretty much the raw key event, except
that a <code>stop()</code> method is always added to it. You
could feed it to, for example, <code>jQuery.Event</code> to
further normalize it.<br>This function can inspect the key
event, and handle it if it wants to. It may return true to tell
CodeMirror to ignore the event. Be wary that, on some browsers,
stopping a <code>keydown</code> does not stop
the <code>keypress</code> from firing, whereas on others it
does. If you respond to an event, you should probably inspect
its <code>type</code> property and only do something when it
is <code>keydown</code> (or <code>keypress</code> for actions
that need character data).</dd>
</dl>
<h2 id="styling">Customized Styling</h2>
<p>Up to a certain extent, CodeMirror's look can be changed by
modifying style sheet files. The style sheets supplied by modes
simply provide the colors for that mode, and can be adapted in a
very straightforward way. To style the editor itself, it is
possible to alter or override the styles defined
in <a href="lib/codemirror.css"><code>codemirror.css</code></a>.</p>
<p>Some care must be taken there, since a lot of the rules in this
file are necessary to have CodeMirror function properly. Adjusting
colors should be safe, of course, and with some care a lot of
other things can be changed as well. The CSS classes defined in
this file serve the following roles:</p>
<dl>
<dt id="class_CodeMirror"><code>CodeMirror</code></dt>
<dd>The outer element of the editor. This determines whether the
editor scrolls (<code>overflow: auto</code> + fixed height). Can
also be used to set styles that should hold for everything
inside the editor, or to set a background.</dd>
<dt id="class_CodeMirror_focused"><code>CodeMirror-focused</code></dt>
<dd>Whenever the editor is focused, the top element gets this
class. This is used to hide the cursor and give the selection a
different color when the editor is not focused.</dd>
<dt id="class_CodeMirror_gutter"><code>CodeMirror-gutter</code></dt>
<dd>Use this for giving a background or a border to the editor
gutter. Don't set any padding here,
use <code>CodeMirror-gutter-text</code> for that. By default,
the gutter is 'fluid', meaning it will adjust its width to the
maximum line number or line marker width. You can also set a
fixed width if you want.</dd>
<dt id="class_CodeMirror_gutter_text"><code>CodeMirror-gutter-text</code></dt>
<dd>Used to style the actual line numbers. For the numbers to
line up, you'll want this style to use exactly the same font and
vertical padding as normal edited text, as per
the <code>CodeMirror-lines</code> class.</dd>
<dt id="class_CodeMirror_lines"><code>CodeMirror-lines</code></dt>
<dd>The visible lines. If this has vertical
padding, <code>CodeMirror-gutter</code> should have the same
padding.</dd>
<dt id="class_CodeMirror_cursor"><code>CodeMirror-cursor</code></dt>
<dd>The cursor is a block element that is absolutely positioned.
You can make it look whichever way you want.</dd>
<dt id="class_CodeMirror_selected"><code>CodeMirror-selected</code></dt>
<dd>The selection is represented by <code>span</code> elements
with this class.</dd>
<dt id="class_CodeMirror_matchingbracket"><code>CodeMirror-matchingbracket</code>,
<code>CodeMirror-nonmatchingbracket</code></dt>
<dd>These are used to style matched (or unmatched) brackets.</dd>
</dl>
<p>The actual lines, as well as the cursor, are represented
by <code>pre</code> elements. By default no text styling (such as
bold) that might change line height is applied. If you do want
such effects, you'll have to give <code>CodeMirror pre</code> a
fixed height. Also, you must still take care that character width
is constant.</p>
<p>If your page's style sheets do funky things to
all <code>div</code> or <code>pre</code> elements (you probably
shouldn't do that), you'll have to define rules to cancel these
effects out again for elements under the <code>CodeMirror</code>
class.</p>
<h2 id="api">Programming API</h2>
<p>A lot of CodeMirror features are only available through its API.
This has the disadvantage that you need to do work to enable them,
and the advantage that CodeMirror will fit seamlessly into your
application.</p>
<p>Whenever points in the document are represented, the API uses
objects with <code>line</code> and <code>ch</code> properties.
Both are zero-based. CodeMirror makes sure to 'clip' any positions
passed by client code so that they fit inside the document, so you
shouldn't worry too much about sanitizing your coordinates. If you
give <code>ch</code> a value of <code>null</code>, or don't
specify it, it will be replaced with the length of the specified
line.</p>
<dl>
<dt id="getValue"><code>getValue() → string</code></dt>
<dd>Get the current editor content.</dd>
<dt id="setValue"><code>setValue(string)</code></dt>
<dd>Set the editor content.</dd>
<dt id="getSelection"><code>getSelection() → string</code></dt>
<dd>Get the currently selected code.</dd>
<dt id="replaceSelection"><code>replaceSelection(string)</code></dt>
<dd>Replace the selection with the given string.</dd>
<dt id="focus"><code>focus()</code></dt>
<dd>Give the editor focus.</dd>
<dt id="setOption"><code>setOption(option, value)</code></dt>
<dd>Change the configuration of the editor. <code>option</code>
should the name of an <a href="#config">option</a>,
and <code>value</code> should be a valid value for that
option.</dd>
<dt id="getOption"><code>getOption(option) → value</code></dt>
<dd>Retrieves the current value of the given option for this
editor instance.</dd>
<dt id="cursorCoords"><code>cursorCoords(start) → object</code></dt>
<dd>Returns an <code>{x, y, yBot}</code> object containing the
coordinates of the cursor relative to the top-left corner of the
page. <code>yBot</code> is the coordinate of the bottom of the
cursor. <code>start</code> is a boolean indicating whether you
want the start or the end of the selection.</dd>
<dt id="charCoords"><code>charCoords(pos) → object</code></dt>
<dd>Like <code>cursorCoords</code>, but returns the position of
an arbitrary characters. <code>pos</code> should be
a <code>{line, ch}</code> object.</dd>
<dt id="coordsChar"><code>coordsChar(object) → pos</code></dt>
<dd>Given an <code>{x, y}</code> object (in page coordinates),
returns the <code>{line, ch}</code> position that corresponds to
it.</dd>
<dt id="undo"><code>undo()</code></dt>
<dd>Undo one edit (if any undo events are stored).</dd>
<dt id="redo"><code>redo()</code></dt>
<dd>Redo one undone edit.</dd>
<dt id="historySize"><code>historySize() → object</code></dt>
<dd>Returns an object with <code>{undo, redo}</code> properties,
both of which hold integers, indicating the amount of stored
undo and redo operations.</dd>
<dt id="indentLine"><code>indentLine(line)</code></dt>
<dd>Reset the given line's indentation to the indentation
prescribed by the mode.</dd>
<dt id="getSearchCursor"><code>getSearchCursor(query, start, caseFold) → cursor</code></dt>
<dd>Used to implement search/replace
functionality. <code>query</code> can be a regular expression or
a string (only strings will match across lines—if they contain
newlines). <code>start</code> provides the starting position of
the search. It can be a <code>{line, ch}</code> object, or can
be left off to default to the start of the
document. <code>caseFold</code> is only relevant when matching a
string. It will cause the search to be case-insensitive. A
search cursor has the following methods:
<dl>
<dt><code>findNext(), findPrevious() → boolean</code></dt>
<dd>Search forward or backward from the current position.
The return value indicates whether a match was found. If
matching a regular expression, the return value will be the
array returned by the <code>match</code> method, in case you
want to extract matched groups.</dd>
<dt><code>from(), to() → object</code></dt>
<dd>These are only valid when the last call
to <code>findNext</code> or <code>findPrevious</code> did
not return false. They will return <code>{line, ch}</code>
objects pointing at the start and end of the match.</dd>
</dl></dd>
<dt id="getTokenAt"><code>getTokenAt(pos) → object</code></dt>
<dd>Retrieves information about the token the current mode found
at the given position (a <code>{line, ch}</code> object). The
returned object has the following properties:
<dl>
<dt><code>start</code></dt><dd>The character (on the given line) at which the token starts.</dd>
<dt><code>end</code></dt><dd>The character at which the token ends.</dd>
<dt><code>string</code></dt><dd>The token's string.</dd>
<dt><code>className</code></dt><dd>The class the mode assigned
to the token. (Can be null when no class was assigned.)</dd>
</dl></dd>
<dt id="markText"><code>markText(from, to, className) → function</code></dt>
<dd>Can be used to mark a range of text with a specific CSS
class name. <code>from</code> and <code>to</code> should
be <code>{line, ch}</code> objects. The method will return a
function that can be called to remove the marking.</dd>
<dt id="setMarker"><code>setMarker(line, text, className) → lineHandle</code></dt>
<dd>Add a gutter marker for the given line. Gutter markers are
shown in the line-number area (instead of the number for this
line). Both <code>text</code> and <code>className</code> are
optional. Setting <code>text</code> to a Unicode character like
● tends to give a nice effect. To put a picture in the gutter,
set <code>text</code> to a space and <code>className</code> to
something that sets a background image. If you
specify <code>text</code>, the given text (which may contain
HTML) will, by default, replace the line number for that line.
If this is not what you want, you can include the
string <code>%N%</code> in the text, which will be replaced by
the line number.</dd>
<dt id="clearMarker"><code>clearMarker(line)</code></dt>
<dd>Clears a marker created
with <code>setMarker</code>. <code>line</code> can be either a
number or a handle returned by <code>setMarker</code> (since a
number may now refer to a different line if something was added
or deleted).</dd>
<dt id="setLineClass"><code>setLineClass(line, className) → lineHandle</code></dt>
<dd>Set a CSS class name for the given line. <code>line</code>
can be a number or a line handle (as returned
by <code>setMarker</code> or this function).
Pass <code>null</code> to clear the class for a line.</dd>
<dt id="lineInfo"><code>lineInfo(line) → object</code></dt>
<dd>Returns the line number, text content, and marker status of
the given line, which can be either a number or a handle
returned by <code>setMarker</code>. The returned object has the
structure <code>{line, text, markerText, markerClass}</code>.</dd>
<dt id="addWidget"><code>addWidget(pos, node, scrollIntoView)</code></dt>
<dd>Puts <code>node</code>, which should be an absolutely
positioned DOM node, into the editor, positioned right below the
given <code>{line, ch}</code> position.
When <code>scrollIntoView</code> is true, the editor will ensure
that the entire node is visible (if possible). To remove the
widget again, simply use DOM methods (move it somewhere else, or
call <code>removeChild</code> on its parent).</dd>
<dt id="matchBrackets"><code>matchBrackets()</code></dt>
<dd>Force matching-bracket-highlighting to happen.</dd>
<dt id="lineCount"><code>lineCount() → number</code></dt>
<dd>Get the number of lines in the editor.</dd>
<dt id="getCursor"><code>getCursor(start) → object</code></dt>
<dd><code>start</code> is a boolean indicating whether the start
or the end of the selection must be retrieved. If it is not
given, the current cursor pos, i.e. the side of the selection
that would move if you pressed an arrow key, is chosen.
A <code>{line, ch}</code> object will be returned.</dd>
<dt id="somethingSelected"><code>somethingSelected() → boolean</code></dt>
<dd>Return true if any text is selected.</dd>
<dt id="setCursor"><code>setCursor(pos)</code></dt>
<dd>Set the cursor position. You can either pass a
single <code>{line, ch}</code> object, or the line and the
character as two separate parameters.</dd>
<dt id="setSelection"><code>setSelection(start, end)</code></dt>
<dd>Set the selection range. <code>start</code>
and <code>end</code> should be <code>{line, ch}</code> objects.</dd>
<dt id="getLine"><code>getLine(n) → string</code></dt>
<dd>Get the content of line <code>n</code>.</dd>
<dt id="setLine"><code>setLine(n, text)</code></dt>
<dd>Set the content of line <code>n</code>.</dd>
<dt id="removeLine"><code>removeLine(n)</code></dt>
<dd>Remove the given line from the document.</dd>
<dt id="getRange"><code>getRange(from, to) → string</code></td>
<dd>Get the text between the given points in the editor, which
should be <code>{line, ch}</code> objects.</dd>
<dt id="replaceRange"><code>replaceRange(string, from, to)</code></dt>
<dd>Replace the part of the document between <code>from</code>
and <code>to</code> with the given string. <code>from</code>
and <code>to</code> must be <code>{line, ch}</code>
objects. <code>to</code> can be left off to simply insert the
string at position <code>from</code>.</dd>
</dl>
<p>The following are more low-level methods:</p>
<dl>
<dt id="operation"><code>operation(func) → result</code></dt>
<dd>CodeMirror internally buffers changes and only updates its
DOM structure after it has finished performing some operation.
If you need to perform a lot of operations on a CodeMirror
instance, you can call this method with a function argument. It
will call the function, buffering up all changes, and only doing
the expensive update after the function returns. This can be a
lot faster. The return value from this method will be the return
value of your function.</dd>
<dt id="refresh"><code>refresh()</code></dt>
<dd>If your code does something to change the size of the editor
element (window resizes are already listened for), or unhides
it, you should probably follow up by calling this method to
ensure CodeMirror is still looking as intended.</dd>
<dt id="getInputField"><code>getInputField() → textarea</code></dt>
<dd>Returns the hiden textarea used to read input.</dd>
<dt id="getWrapperElement"><code>getWrapperElement() → node</code></dt>
<dd>Returns the DOM node that represents the editor. Remove this
from your tree to delete an editor instance.</dd>
</dl>
<p id="fromTextArea">Finally, the <code>CodeMirror</code> object
itself has a method <code>fromTextArea</code>. This takes a
textarea DOM node as first argument and an optional configuration
object as second. It will replace the textarea with a CodeMirror
instance, and wire up the form of that textarea (if any) to make
sure the editor contents are put into the textarea when the form
is submitted. A CodeMirror instance created this way has two
additional methods:</p>
<dl>
<dt id="save"><code>save()</code></dt>
<dd>Copy the content of the editor into the textarea.</dd>
<dt id="toTextArea"><code>toTextArea()</code></dt>
<dd>Remove the editor, and restore the original textarea (with
the editor's current content).</dd>
</dl>
<h2 id="modeapi">Writing CodeMirror Modes</h2>
<p>Modes typically consist of a JavaScript file and a CSS file.
The CSS file (see, for
example <a href="mode/javascript/javascript.css"><code>javascript.css</code></a>)
defines the classes that will be used to style the syntactic
elements of the code, and the script contains the logic to
actually assign these classes to the right pieces of text.</p>
<p>You'll usually want to use some kind of prefix for your CSS
classes, so that they are unlikely to clash with other classes,
both those used by other modes and those defined by the page in
which CodeMirror is embedded.</p>
<p id="defineMode">The mode script should
call <code>CodeMirror.defineMode</code> to register itself with
CodeMirror. This function takes two arguments. The first should be
the name of the mode, for which you should use a lowercase string,
preferably one that is also the name of the files that define the
mode (i.e. <code>"xml"</code> is defined <code>xml.js</code>). The
second argument should be a function that, given a CodeMirror
configuration object (the thing passed to
the <code>CodeMirror</code> function) and a mode configuration
object (as in the <a href="#option_mode"><code>mode</code></a>
option), returns a mode object.</p>
<p>Typically, you should use this second argument
to <code>defineMode</code> as your module scope function (modes
should not leak anything into the global scope!), i.e. write your
whole mode inside this function.</p>
<p>The main responsibility of a mode script is <em>parsing</em>
the content of the editor. Depending on the language and the
amount of functionality desired, this can be done in really easy
or extremely complicated ways. Some parsers can be stateless,
meaning that they look at one element (<em>token</em>) of the code
at a time, with no memory of what came before. Most, however, will
need to remember something. This is done by using a <em>state
object</em>, which is an object that can be mutated every time a
new token is read.</p>
<p id="startState">Modes that use a state must define
a <code>startState</code> method on their mode object. This is a
function of no arguments that produces a state object to be used
at the start of a document.</p>
<p id="token">The most important part of a mode object is
its <code>token(stream, state)</code> method. All modes must
define this method. It should read one token from the stream it is
given as an argument, optionally update its state, and return a
CSS class string, or <code>null</code> for tokens that do not have
to be styled.<p>
<p id="blankLine">By default, blank lines are simply skipped when
tokenizing a document. For languages that have significant blank
lines, you can define a <code>blankLine(state)</code> method on
your mode that will get called whenever a blank line is passed
over, so that it can update the parser state.</p>
<p id="StringStream">The stream object encapsulates a line of code
(tokens may never span lines) and our current position in that
line. It has the following API:</p>
<dl>
<dt><code>eol() → boolean</code></dt>
<dd>Returns true only if the stream is at the end of the
line.</dd>
<dt><code>sol() → boolean</code></dt>
<dd>Returns true only if the stream is at the start of the
line.</dd>
<dt><code>peek() → character</code></dt>
<dd>Returns the next character in the stream without advancing
it. Will return <code>undefined</code> at the end of the
line.</dd>
<dt><code>next() → character</code></dt>
<dd>Returns the next character in the stream and advances it.
Also returns <code>undefined</code> when no more characters are
available.</dd>
<dt><code>eat(match) → character</code></dt>
<dd><code>match</code> can be a character, a regular expression,
or a function that takes a character and returns a boolean. If
the next character in the stream 'matches' the given argument,
it is consumed and returned. Otherwise, <code>undefined</code>
is returned.</dd>
<dt><code>eatWhile(match) → boolean</code></dt>
<dd>Repeatedly calls <code>eat</code> with the given argument,
until it fails. Returns true if any characters were eaten.</dd>
<dt><code>eatSpace() → boolean</code></dt>
<dd>Shortcut for <code>eatWhile</code> when matching
white-space.</dd>
<dt><code>skipToEnd()</code></dt>
<dd>Moves the position to the end of the line.</dd>
<dt><code>skipTo(ch) → boolean</code></dt>
<dd>Skips to the next occurrence of the given character, if
found. Returns true if the character was found.</dd>
<dt><code>match(pattern, consume, caseFold) → boolean</code></dt>
<dd>Act like a
multi-character <code>eat</code>—if <code>consume</code> is true
or not given—or a look-ahead that doesn't update the stream
position—if it is false. <code>pattern</code> can be either a
string or a regular expression starting with <code>^</code>.
When it is a string, <code>caseFold</code> can be set to true to
make the match case-insensitive. When successfully matching a
regular expression, the returned value will be the array
returned by <code>match</code>, in case you need to extract
matched groups.</dd>
<dt><code>backUp(n)</code></dt>
<dd>Backs up the stream <code>n</code> characters. Backing it up
further than the start of the current token will cause things to
break, so be careful.</dd>
<dt><code>column() → integer</code></dt>
<dd>Returns the column (taking into account tabs) at which the
current token starts. Can be used to find out whether a token
starts a new line.</dd>
<dt><code>indentation() → integer</code></dt>
<dd>Tells you how far the current line has been indented, in
spaces. Corrects for tab characters.</dd>
<dt><code>current() → string</code></dt>
<dd>Get the string between the start of the current token and
the current stream position.</dd>
</dl>
<p id="copyState">Because state object are mutated, and CodeMirror
needs to keep valid versions of a state around so that it can
restart a parse at any line, copies must be made of state objects.
The default algorithm used is that a new state object is created,
which gets all the properties of the old object. Any properties
which hold arrays get a copy of these arrays (since arrays tend to
be used as mutable stacks). When this is not correct, for example
because a mode mutates non-array properties of its state object, a
mode object should define a <code>copyState</code> method,
which is given a state and should return a safe copy of that
state.</p>
<p id="indent">If you want your mode to provide smart indentation
(see <a href="#option_enterMode"><code>entermode</code></a>
and <a href="#option_tabMode"><code>tabMode</code></a> when they
have a value of <code>"indent"</code>), you must define
an <code>indent(state, textAfter)</code> method on your mode
object.</p>
<p>The indentation method should inspect the given state object,
and optionally the <code>textAfter</code> string, which contains
the text on the line that is being indented, and return an
integer, the amount of spaces to indent. It should usually take
the <a href="#option_indentUnit"><code>indentUnit</code></a>
option into account.</p>
<p id="electricChars">Finally, a mode may define
an <code>electricChars</code> property, which should hold a string
containing all the characters that should trigger the behaviour
described for
the <a href="#option_electricChars"><code>electricChars</code></a>
option.</p>
<p>So, to summarize, a mode <em>must</em> provide
a <code>token</code> method, and it <em>may</em>
provide <code>startState</code>, <code>copyState</code>,
and <code>indent</code> methods. For an example of a trivial mode,
see the <a href="mode/diff/diff.js">diff mode</a>, for a more
involved example, see
the <a href="mode/javascript/javascript.js">JavaScript
mode</a>.</p>
<p>Sometimes, it is useful for modes to <em>nest</em>—to have one
mode delegate work to another mode. An example of this kind of
mode is the <a href="mode/htmlmixed/htmlmixed.js">mixed-mode HTML
mode</a>. To implement such nesting, it is usually necessary to
create mode objects and copy states yourself. To create a mode
object, there are <code>CodeMirror.getMode(options,
parserConfig)</code>, where the first argument is a configuration
object as passed to the mode constructor function, and the second
argument is a mode specification as in
the <a href="#option_mode"><code>mode</code></a> option. To copy a
state object, call <code>CodeMirror.copyState(mode, state)</code>,
where <code>mode</code> is the mode that created the given
state.</p>
<p>To make indentation work properly in a nested parser, it is
advisable to give the <code>startState</code> method of modes that
are intended to be nested an optional argument that provides the
base indentation for the block of code. The JavaScript and CSS
parser do this, for example, to allow JavaScript and CSS code
inside the mixed-mode HTML mode to be properly indented.</p>
<p>Finally, it is possible to associate your mode, or a certain
configuration of your mode, with
a <a href="http://en.wikipedia.org/wiki/MIME">MIME</a> type. For
example, the JavaScript mode associates itself
with <code>text/javascript</code>, and its JSON variant
with <code>application/json</code>. To do this,
call <code>CodeMirror.defineMIME(mime, modeSpec)</code>,
where <code>modeSpec</code> can be a string or object specifying a
mode, as in the <a href="#option_mode"><code>mode</code></a>
option.</p>
</div><div class="rightsmall blk">
<h2>Contents</h2>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#usage">Basic Usage</a></li>
<li><a href="#config">Configuration</a></li>
<li><a href="#styling">Customized Styling</a></li>
<li><a href="#api">Programming API</a></li>
<li><a href="#modeapi">Writing CodeMirror Modes</a></li>
</ul>
</div></div>
<div style="height: 2em">&nbsp;</div>
<script type="text/javascript" src="css/font.js"></script>
</body>
</html>

7
js/codemirror/mode/clike/clike.css vendored Normal file
View File

@ -0,0 +1,7 @@
span.c-like-keyword {color: #90b;}
span.c-like-number {color: #291;}
span.c-like-comment {color: #a70;}
span.c-like-string {color: #a22;}
span.c-like-preprocessor {color: #049;}
span.c-like-var {color: #22b;}
span.c-like-annotation {color: #666;}

187
js/codemirror/mode/clike/clike.js vendored Normal file
View File

@ -0,0 +1,187 @@
CodeMirror.defineMode("clike", function(config, parserConfig) {
var indentUnit = config.indentUnit, keywords = parserConfig.keywords,
cpp = parserConfig.useCPP, multiLineStrings = parserConfig.multiLineStrings,
$vars = parserConfig.$vars, atAnnotations = parserConfig.atAnnotations;
var isOperatorChar = /[+\-*&%=<>!?|]/;
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
var type;
function ret(tp, style) {
type = tp;
return style;
}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'")
return chain(stream, state, tokenString(ch));
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
return ret(ch);
else if (ch == "#" && cpp && state.startOfLine) {
stream.skipToEnd();
return ret("directive", "c-like-preprocessor");
}
else if (/\d/.test(ch)) {
stream.eatWhile(/[\w\.]/)
return ret("number", "c-like-number");
}
else if (ch == "/") {
if (stream.eat("*")) {
return chain(stream, state, tokenComment);
}
else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "c-like-comment");
}
else {
stream.eatWhile(isOperatorChar);
return ret("operator");
}
}
else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return ret("operator");
}
else if (atAnnotations && ch == "@") {
stream.eatWhile(/[\w\$_]/);
return ret("annotation", "c-like-annotation");
}
else if ($vars && ch == "$") {
stream.eatWhile(/[\w\$_]/);
return ret("word", "c-like-var");
}
else {
stream.eatWhile(/[\w\$_]/);
if (keywords && keywords.propertyIsEnumerable(stream.current())) return ret("keyword", "c-like-keyword");
return ret("word", "c-like-word");
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote && !escaped) {end = true; break;}
escaped = !escaped && next == "\\";
}
if (end || !(escaped || multiLineStrings))
state.tokenize = tokenBase;
return ret("string", "c-like-string");
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "c-like-comment");
}
function Context(indented, column, type, align, prev) {
this.indented = indented;
this.column = column;
this.type = type;
this.align = align;
this.prev = prev;
}
function pushContext(state, col, type) {
return state.context = new Context(state.indented, col, type, null, state.context);
}
function popContext(state) {
return state.context = state.context.prev;
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: tokenBase,
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
indented: 0,
startOfLine: true
};
},
token: function(stream, state) {
var ctx = state.context;
if (stream.sol()) {
if (ctx.align == null) ctx.align = false;
state.indented = stream.indentation();
state.startOfLine = true;
}
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
if (ctx.align == null) ctx.align = true;
if ((type == ";" || type == ":") && ctx.type == "statement") popContext(state);
else if (type == "{") pushContext(state, stream.column(), "}");
else if (type == "[") pushContext(state, stream.column(), "]");
else if (type == "(") pushContext(state, stream.column(), ")");
else if (type == "}") {
if (ctx.type == "statement") ctx = popContext(state);
if (ctx.type == "}") ctx = popContext(state);
if (ctx.type == "statement") ctx = popContext(state);
}
else if (type == ctx.type) popContext(state);
else if (ctx.type == "}" || ctx.type == "top") pushContext(state, stream.column(), "statement");
state.startOfLine = false;
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type;
if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
else if (ctx.align) return ctx.column + (closing ? 0 : 1);
else return ctx.indented + (closing ? 0 : indentUnit);
},
electricChars: "{}"
};
});
(function() {
function keywords(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}
var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
"double static else struct entry switch extern typedef float union for unsigned " +
"goto while enum void const signed volatile";
CodeMirror.defineMIME("text/x-csrc", {
name: "clike",
useCPP: true,
keywords: keywords(cKeywords)
});
CodeMirror.defineMIME("text/x-c++src", {
name: "clike",
useCPP: true,
keywords: keywords(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
"static_cast typeid catch false operator template typename class friend private " +
"this using const_cast inline public throw virtual delete mutable protected true " +
"wchar_t")
});
CodeMirror.defineMIME("text/x-java", {
name: "clike",
atAnnotations: true,
keywords: keywords("abstract assert boolean break byte case catch char class const continue default " +
"do double else enum extends false final finally float for goto if implements import " +
"instanceof int interface long native new null package private protected public " +
"return short static strictfp super switch synchronized this throw throws transient " +
"true try void volatile while")
});
}());

101
js/codemirror/mode/clike/index.html vendored Normal file
View File

@ -0,0 +1,101 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: C-like mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="clike.js"></script>
<link rel="stylesheet" href="clike.css">
<link rel="stylesheet" href="../../css/docs.css">
<style>.CodeMirror {border: 2px inset #dee;}</style>
</head>
<body>
<h1>CodeMirror 2: C-like mode</h1>
<form><textarea id="code" name="code">
/* C demo code */
#include <zmq.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include <stdio.h>
#include <fcntl.h>
#include <malloc.h>
typedef struct {
void* arg_socket;
zmq_msg_t* arg_msg;
char* arg_string;
unsigned long arg_len;
int arg_int, arg_command;
int signal_fd;
int pad;
void* context;
sem_t sem;
} acl_zmq_context;
#define p(X) (context->arg_##X)
void* zmq_thread(void* context_pointer) {
acl_zmq_context* context = (acl_zmq_context*)context_pointer;
char ok = 'K', err = 'X';
int res;
while (1) {
while ((res = sem_wait(&amp;context->sem)) == EINTR);
if (res) {write(context->signal_fd, &amp;err, 1); goto cleanup;}
switch(p(command)) {
case 0: goto cleanup;
case 1: p(socket) = zmq_socket(context->context, p(int)); break;
case 2: p(int) = zmq_close(p(socket)); break;
case 3: p(int) = zmq_bind(p(socket), p(string)); break;
case 4: p(int) = zmq_connect(p(socket), p(string)); break;
case 5: p(int) = zmq_getsockopt(p(socket), p(int), (void*)p(string), &amp;p(len)); break;
case 6: p(int) = zmq_setsockopt(p(socket), p(int), (void*)p(string), p(len)); break;
case 7: p(int) = zmq_send(p(socket), p(msg), p(int)); break;
case 8: p(int) = zmq_recv(p(socket), p(msg), p(int)); break;
case 9: p(int) = zmq_poll(p(socket), p(int), p(len)); break;
}
p(command) = errno;
write(context->signal_fd, &amp;ok, 1);
}
cleanup:
close(context->signal_fd);
free(context_pointer);
return 0;
}
void* zmq_thread_init(void* zmq_context, int signal_fd) {
acl_zmq_context* context = malloc(sizeof(acl_zmq_context));
pthread_t thread;
context->context = zmq_context;
context->signal_fd = signal_fd;
sem_init(&amp;context->sem, 1, 0);
pthread_create(&amp;thread, 0, &amp;zmq_thread, context);
pthread_detach(thread);
return context;
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-csrc"
});
</script>
<p>Simple mode that tries to handle C-like languages as well as it
can. Takes two configuration parameters: <code>keywords</code>, an
object whose property names are the keywords in the language,
and <code>useCPP</code>, which determines whether C preprocessor
directives are recognized.</p>
<p><strong>MIME types defined:</strong> <code>text/x-csrc</code>
(C code), <code>text/x-c++src</code> (C++
code), <code>text/x-java</code> (Java code).</p>
</body>
</html>

9
js/codemirror/mode/css/css.css vendored Normal file
View File

@ -0,0 +1,9 @@
span.css-at {color: #708;}
span.css-unit {color: #281;}
span.css-value {color: #708;}
span.css-identifier {color: black;}
span.css-selector {color: #11B;}
span.css-important {color: #00F;}
span.css-colorcode {color: #299;}
span.css-comment {color: #A70;}
span.css-string {color: #A22;}

124
js/codemirror/mode/css/css.js vendored Normal file
View File

@ -0,0 +1,124 @@
CodeMirror.defineMode("css", function(config) {
var indentUnit = config.indentUnit, type;
function ret(style, tp) {type = tp; return style;}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == "@") {stream.eatWhile(/\w/); return ret("css-at", stream.current());}
else if (ch == "/" && stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
else if (ch == "<" && stream.eat("!")) {
state.tokenize = tokenSGMLComment;
return tokenSGMLComment(stream, state);
}
else if (ch == "=") ret(null, "compare");
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
else if (ch == "#") {
stream.eatWhile(/\w/);
return ret("css-selector", "hash");
}
else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("css-important", "important");
}
else if (/\d/.test(ch)) {
stream.eatWhile(/[\w.%]/);
return ret("css-unit", "unit");
}
else if (/[,.+>*\/]/.test(ch)) {
return ret(null, "select-op");
}
else if (/[;{}:\[\]]/.test(ch)) {
return ret(null, ch);
}
else {
stream.eatWhile(/[\w\\\-_]/);
return ret("css-identifier", "identifier");
}
}
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("css-comment", "comment");
}
function tokenSGMLComment(stream, state) {
var dashes = 0, ch;
while ((ch = stream.next()) != null) {
if (dashes >= 2 && ch == ">") {
state.tokenize = tokenBase;
break;
}
dashes = (ch == "-") ? dashes + 1 : 0;
}
return ret("css-comment", "comment");
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped)
break;
escaped = !escaped && ch == "\\";
}
if (!escaped) state.tokenize = tokenBase;
return ret("css-string", "string");
};
}
return {
startState: function(base) {
return {tokenize: tokenBase,
baseIndent: base || 0,
stack: []};
},
token: function(stream, state) {
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
var context = state.stack[state.stack.length-1];
if (type == "hash" && context == "rule") style = "css-colorcode";
else if (style == "css-identifier") {
if (context == "rule") style = "css-value";
else if (!context || context == "@media{") style = "css-selector";
}
if (context == "rule" && /^[\{\};]$/.test(type))
state.stack.pop();
if (type == "{") {
if (context == "@media") state.stack[state.stack.length-1] = "@media{";
else state.stack.push("{");
}
else if (type == "}") state.stack.pop();
else if (type == "@media") state.stack.push("@media");
else if (context != "rule" && context != "@media" && type != "comment") state.stack.push("rule");
return style;
},
indent: function(state, textAfter) {
var n = state.stack.length;
if (/^\}/.test(textAfter))
n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
return state.baseIndent + n * indentUnit;
},
electricChars: "}"
};
});
CodeMirror.defineMIME("text/css", "css");

56
js/codemirror/mode/css/index.html vendored Normal file
View File

@ -0,0 +1,56 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: CSS mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="css.js"></script>
<link rel="stylesheet" href="css.css">
<style>.CodeMirror {background: #f8f8f8;}</style>
<link rel="stylesheet" href="../../css/docs.css">
</head>
<body>
<h1>CodeMirror 2: CSS mode</h1>
<form><textarea id="code" name="code">
/* Some example CSS */
@import url("something.css");
body {
margin: 0;
padding: 3em 6em;
font-family: tahoma, arial, sans-serif;
color: #000;
}
#navigation a {
font-weight: bold;
text-decoration: none !important;
}
h1 {
font-size: 2.5em;
}
h2 {
font-size: 1.7em;
}
h1:before, h2:before {
content: "::";
}
code {
font-family: courier, monospace;
font-size: 80%;
color: #418A8A;
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script>
<p><strong>MIME types defined:</strong> <code>text/css</code>.</p>
</body>
</html>

3
js/codemirror/mode/diff/diff.css vendored Normal file
View File

@ -0,0 +1,3 @@
span.diff-rangeinfo {color: #a0b;}
span.diff-minus {color: #a22;}
span.diff-plus {color: #2b2;}

13
js/codemirror/mode/diff/diff.js vendored Normal file
View File

@ -0,0 +1,13 @@
CodeMirror.defineMode("diff", function() {
return {
token: function(stream) {
var ch = stream.next();
stream.skipToEnd();
if (ch == "+") return "diff-plus";
if (ch == "-") return "diff-minus";
if (ch == "@") return "diff-rangeinfo";
}
};
});
CodeMirror.defineMIME("text/x-diff", "diff");

99
js/codemirror/mode/diff/index.html vendored Normal file
View File

@ -0,0 +1,99 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Diff mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="diff.js"></script>
<link rel="stylesheet" href="diff.css">
<style>.CodeMirror {border-top: 1px solid #ddd; border-bottom: 1px solid #ddd;}</style>
<link rel="stylesheet" href="../../css/docs.css">
</head>
<body>
<h1>CodeMirror 2: Diff mode</h1>
<form><textarea id="code" name="code">
diff --git a/index.html b/index.html
index c1d9156..7764744 100644
--- a/index.html
+++ b/index.html
@@ -95,7 +95,8 @@ StringStream.prototype = {
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
- autoMatchBrackets: true
+ autoMatchBrackets: true,
+ onGutterClick: function(x){console.log(x);}
});
</script>
</body>
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 04646a9..9a39cc7 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -399,10 +399,16 @@ var CodeMirror = (function() {
}
function onMouseDown(e) {
- var start = posFromMouse(e), last = start;
+ var start = posFromMouse(e), last = start, target = e.target();
if (!start) return;
setCursor(start.line, start.ch, false);
if (e.button() != 1) return;
+ if (target.parentNode == gutter) {
+ if (options.onGutterClick)
+ options.onGutterClick(indexOf(gutter.childNodes, target) + showingFrom);
+ return;
+ }
+
if (!focused) onFocus();
e.stop();
@@ -808,7 +814,7 @@ var CodeMirror = (function() {
for (var i = showingFrom; i < showingTo; ++i) {
var marker = lines[i].gutterMarker;
if (marker) html.push('<div class="' + marker.style + '">' + htmlEscape(marker.text) + '</div>');
- else html.push("<div>" + (options.lineNumbers ? i + 1 : "\u00a0") + "</div>");
+ else html.push("<div>" + (options.lineNumbers ? i + options.firstLineNumber : "\u00a0") + "</div>");
}
gutter.style.display = "none"; // TODO test whether this actually helps
gutter.innerHTML = html.join("");
@@ -1371,10 +1377,8 @@ var CodeMirror = (function() {
if (option == "parser") setParser(value);
else if (option === "lineNumbers") setLineNumbers(value);
else if (option === "gutter") setGutter(value);
- else if (option === "readOnly") options.readOnly = value;
- else if (option === "indentUnit") {options.indentUnit = indentUnit = value; setParser(options.parser);}
- else if (/^(?:enterMode|tabMode|indentWithTabs|readOnly|autoMatchBrackets|undoDepth)$/.test(option)) options[option] = value;
- else throw new Error("Can't set option " + option);
+ else if (option === "indentUnit") {options.indentUnit = value; setParser(options.parser);}
+ else options[option] = value;
},
cursorCoords: cursorCoords,
undo: operation(undo),
@@ -1402,7 +1406,8 @@ var CodeMirror = (function() {
replaceRange: operation(replaceRange),
operation: function(f){return operation(f)();},
- refresh: function(){updateDisplay([{from: 0, to: lines.length}]);}
+ refresh: function(){updateDisplay([{from: 0, to: lines.length}]);},
+ getInputField: function(){return input;}
};
return instance;
}
@@ -1420,6 +1425,7 @@ var CodeMirror = (function() {
readOnly: false,
onChange: null,
onCursorActivity: null,
+ onGutterClick: null,
autoMatchBrackets: false,
workTime: 200,
workDelay: 300,
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script>
<p><strong>MIME types defined:</strong> <code>text/x-diff</code>.</p>
</body>
</html>

25
js/codemirror/mode/haskell/haskell.css vendored Normal file
View File

@ -0,0 +1,25 @@
span.hs-char,
span.hs-float,
span.hs-integer,
span.hs-string {color: #762;}
span.hs-comment {color: #262;font-style: italic;}
span.hs-pragma {color: #555;font-style: italic;}
span.hs-special,
span.hs-varid,
span.hs-varsym {color: #000;}
span.hs-conid,
span.hs-consym {color: #b11;}
span.hs-qualifier {color: #555;}
span.hs-reservedid,
span.hs-reservedop {color: #730;}
span.hs-prelude-varid,
span.hs-prelude-varsym {color: #30a;}
span.hs-prelude-conid {color: #b11;}
span.hs-error {background-color: #fdd;}

242
js/codemirror/mode/haskell/haskell.js vendored Normal file
View File

@ -0,0 +1,242 @@
CodeMirror.defineMode("haskell", function(cmCfg, modeCfg) {
function switchState(source, setState, f) {
setState(f);
return f(source, setState);
}
// These should all be Unicode extended, as per the Haskell 2010 report
var smallRE = /[a-z_]/;
var largeRE = /[A-Z]/;
var digitRE = /[0-9]/;
var hexitRE = /[0-9A-Fa-f]/;
var octitRE = /[0-7]/;
var idRE = /[a-z_A-Z0-9']/;
var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
var specialRE = /[(),;[\]`{}]/;
var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
function normal(source, setState) {
if (source.eatWhile(whiteCharRE)) {
return null;
}
var ch = source.next();
if (specialRE.test(ch)) {
if (ch == '{' && source.eat('-')) {
var t = "hs-comment";
if (source.eat('#')) {
t = "hs-pragma";
}
return switchState(source, setState, ncomment(t, 1));
}
return "hs-special";
}
if (ch == '\'') {
if (source.eat('\\')) {
source.next(); // should handle other escapes here
}
else {
source.next();
}
if (source.eat('\'')) {
return "hs-char";
}
return "hs-error";
}
if (ch == '"') {
return switchState(source, setState, stringLiteral);
}
if (largeRE.test(ch)) {
source.eatWhile(idRE);
if (source.eat('.')) {
return "hs-qualifier";
}
return "hs-conid";
}
if (smallRE.test(ch)) {
source.eatWhile(idRE);
return "hs-varid";
}
if (digitRE.test(ch)) {
if (ch == '0') {
if (source.eat(/[xX]/)) {
source.eatWhile(hexitRE); // should require at least 1
return "hs-integer";
}
if (source.eat(/[oO]/)) {
source.eatWhile(octitRE); // should require at least 1
return "hs-integer";
}
}
source.eatWhile(digitRE);
var t = "hs-integer";
if (source.eat('.')) {
t = "hs-float";
source.eatWhile(digitRE); // should require at least 1
}
if (source.eat(/[eE]/)) {
t = "hs-float";
source.eat(/[-+]/);
source.eatWhile(digitRE); // should require at least 1
}
return t;
}
if (symbolRE.test(ch)) {
if (ch == '-' && source.eat(/-/)) {
source.eatWhile(/-/);
if (!source.eat(symbolRE)) {
source.skipToEnd();
return "hs-comment";
}
}
var t = "hs-varsym";
if (ch == ':') {
t = "hs-consym";
}
source.eatWhile(symbolRE);
return t;
}
return "hs-error";
}
function ncomment(type, nest) {
if (nest == 0) {
return normal;
}
return function(source, setState) {
var currNest = nest;
while (!source.eol()) {
var ch = source.next();
if (ch == '{' && source.eat('-')) {
++currNest;
}
else if (ch == '-' && source.eat('}')) {
--currNest;
if (currNest == 0) {
setState(normal);
return type;
}
}
}
setState(ncomment(type, currNest));
return type;
}
}
function stringLiteral(source, setState) {
while (!source.eol()) {
var ch = source.next();
if (ch == '"') {
setState(normal);
return "hs-string";
}
if (ch == '\\') {
if (source.eol() || source.eat(whiteCharRE)) {
setState(stringGap);
return "hs-string";
}
if (source.eat('&')) {
}
else {
source.next(); // should handle other escapes here
}
}
}
setState(normal);
return "hs-error";
}
function stringGap(source, setState) {
if (source.eat('\\')) {
return switchState(source, setState, stringLiteral);
}
source.next();
setState(normal);
return "hs-error";
}
var wellKnownWords = (function() {
var wkw = {};
function setType(t) {
return function () {
for (var i = 0; i < arguments.length; i++)
wkw[arguments[i]] = t;
}
}
setType("hs-reservedid")(
"case", "class", "data", "default", "deriving", "do", "else", "foreign",
"if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
"module", "newtype", "of", "then", "type", "where", "_");
setType("hs-reservedop")(
"\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
setType("hs-prelude-varsym")(
"!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
"==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
setType("hs-prelude-conid")(
"Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
"False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
"IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
"Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
"ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
"String", "True");
setType("hs-prelude-varid")(
"abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
"asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
"compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
"cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
"elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
"enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
"flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
"foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
"fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
"getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
"isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
"lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
"mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
"minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
"otherwise", "pi", "pred", "print", "product", "properFraction",
"putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
"readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
"realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
"round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
"sequence", "sequence_", "show", "showChar", "showList", "showParen",
"showString", "shows", "showsPrec", "significand", "signum", "sin",
"sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
"tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
"toRational", "truncate", "uncurry", "undefined", "unlines", "until",
"unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
"zip3", "zipWith", "zipWith3");
return wkw;
})();
return {
startState: function () { return { f: normal }; },
copyState: function (s) { return { f: s.f }; },
token: function(stream, state) {
var t = state.f(stream, function(s) { state.f = s; });
var w = stream.current();
return (w in wellKnownWords) ? wellKnownWords[w] : t;
}
};
});
CodeMirror.defineMIME("text/x-haskell", "haskell");

59
js/codemirror/mode/haskell/index.html vendored Normal file
View File

@ -0,0 +1,59 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Haskell mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="haskell.js"></script>
<link rel="stylesheet" href="haskell.css">
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<link rel="stylesheet" href="../../css/docs.css">
</head>
<body>
<h1>CodeMirror 2: Haskell mode</h1>
<form><textarea id="code" name="code">
module UniquePerms (
uniquePerms
)
where
-- | Find all unique permutations of a list where there might be duplicates.
uniquePerms :: (Eq a) => [a] -> [[a]]
uniquePerms = permBag . makeBag
-- | An unordered collection where duplicate values are allowed,
-- but represented with a single value and a count.
type Bag a = [(a, Int)]
makeBag :: (Eq a) => [a] -> Bag a
makeBag [] = []
makeBag (a:as) = mix a $ makeBag as
where
mix a [] = [(a,1)]
mix a (bn@(b,n):bs) | a == b = (b,n+1):bs
| otherwise = bn : mix a bs
permBag :: Bag a -> [[a]]
permBag [] = [[]]
permBag bs = concatMap (\(f,cs) -> map (f:) $ permBag cs) . oneOfEach $ bs
where
oneOfEach [] = []
oneOfEach (an@(a,n):bs) =
let bs' = if n == 1 then bs else (a,n-1):bs
in (a,bs') : mapSnd (an:) (oneOfEach bs)
apSnd f (a,b) = (a, f b)
mapSnd = map . apSnd
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true
});
</script>
<p><strong>MIME types defined:</strong> <code>text/x-haskell</code>.</p>
</body>
</html>

View File

@ -0,0 +1,74 @@
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
var jsMode = CodeMirror.getMode(config, "javascript");
var cssMode = CodeMirror.getMode(config, "css");
function html(stream, state) {
var style = htmlMode.token(stream, state.htmlState);
if (style == "xml-tag" && stream.current() == ">" && state.htmlState.context) {
if (/^script$/i.test(state.htmlState.context.tagName)) {
state.token = javascript;
state.localState = jsMode.startState(htmlMode.indent(state.htmlState, ""));
}
else if (/^style$/i.test(state.htmlState.context.tagName)) {
state.token = css;
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
}
}
return style;
}
function maybeBackup(stream, pat, style) {
var cur = stream.current();
var close = cur.search(pat);
if (close > -1) stream.backUp(cur.length - close);
return style;
}
function javascript(stream, state) {
if (stream.match(/^<\/\s*script\s*>/i, false)) {
state.token = html;
state.curState = null;
return html(stream, state);
}
return maybeBackup(stream, /<\/\s*script\s*>/,
jsMode.token(stream, state.localState));
}
function css(stream, state) {
if (stream.match(/^<\/\s*style\s*>/i, false)) {
state.token = html;
state.localState = null;
return html(stream, state);
}
return maybeBackup(stream, /<\/\s*style\s*>/,
cssMode.token(stream, state.localState));
}
return {
startState: function() {
var state = htmlMode.startState();
return {token: html, localState: null, htmlState: state};
},
copyState: function(state) {
if (state.localState)
var local = CodeMirror.copyState(state.token == css ? cssMode : jsMode, state.localState);
return {token: state.token, localState: local, htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
},
token: function(stream, state) {
return state.token(stream, state);
},
indent: function(state, textAfter) {
if (state.token == html || /^\s*<\//.test(textAfter))
return htmlMode.indent(state.htmlState, textAfter);
else if (state.token == javascript)
return jsMode.indent(state.localState, textAfter);
else
return cssMode.indent(state.localState, textAfter);
},
electricChars: "/{}:"
}
});
CodeMirror.defineMIME("text/html", "htmlmixed");

54
js/codemirror/mode/htmlmixed/index.html vendored Normal file
View File

@ -0,0 +1,54 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: HTML mixed mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../xml/xml.js"></script>
<link rel="stylesheet" href="../xml/xml.css">
<script src="../javascript/javascript.js"></script>
<link rel="stylesheet" href="../javascript/javascript.css">
<script src="../css/css.js"></script>
<link rel="stylesheet" href="../css/css.css">
<script src="htmlmixed.js"></script>
<link rel="stylesheet" href="../../css/docs.css">
<style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
</head>
<body>
<h1>CodeMirror 2: HTML mixed mode</h1>
<form><textarea id="code" name="code">
<html style="color: green">
<!-- this is a comment -->
<head>
<title>Mixed HTML Example</title>
<style type="text/css">
h1 {font-family: comic sans; color: #f0f;}
div {background: yellow !important;}
body {
max-width: 50em;
margin: 1em 2em 1em 5em;
}
</style>
</head>
<body>
<h1>Mixed HTML Example</h1>
<script>
function jsFunc(arg1, arg2) {
if (arg1 && arg2) document.body.innerHTML = "achoo";
}
</script>
</body>
</html>
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", tabMode: "indent"});
</script>
<p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
<p><strong>MIME types defined:</strong> <code>text/html</code>
(redefined, only takes effect if you load this parser after the
XML parser).</p>
</body>
</html>

View File

@ -0,0 +1,78 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: JavaScript mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="javascript.js"></script>
<link rel="stylesheet" href="javascript.css">
<link rel="stylesheet" href="../../css/docs.css">
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
</head>
<body>
<h1>CodeMirror 2: JavaScript mode</h1>
<div><textarea id="code" name="code">
// Demo code (the actual new parser character stream implementation)
function StringStream(string) {
this.pos = 0;
this.string = string;
}
StringStream.prototype = {
done: function() {return this.pos >= this.string.length;},
peek: function() {return this.string.charAt(this.pos);},
next: function() {
if (this.pos &lt; this.string.length)
return this.string.charAt(this.pos++);
},
eat: function(match) {
var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match;
else var ok = ch &amp;&amp; match.test ? match.test(ch) : match(ch);
if (ok) {this.pos++; return ch;}
},
eatWhile: function(match) {
var start = this.pos;
while (this.eat(match));
if (this.pos > start) return this.string.slice(start, this.pos);
},
backUp: function(n) {this.pos -= n;},
column: function() {return this.pos;},
eatSpace: function() {
var start = this.pos;
while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
return this.pos - start;
},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
if (consume !== false) this.pos += str.length;
return true;
}
}
else {
var match = this.string.slice(this.pos).match(pattern);
if (match &amp;&amp; consume !== false) this.pos += match[0].length;
return match;
}
}
};
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true
});
</script>
<p>JavaScript mode supports a single configuration
option, <code>json</code>, which will set the mode to expect JSON
data rather than a JavaScript program.</p>
<p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>.</p>
</body>
</html>

View File

@ -0,0 +1,6 @@
span.js-keyword {color: #90b;}
span.js-atom {color: #291;}
span.js-variabledef {color: #00f;}
span.js-localvariable {color: #049;}
span.js-comment {color: #a70;}
span.js-string {color: #a22;}

View File

@ -0,0 +1,348 @@
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var jsonMode = parserConfig.json;
// Tokenizer
var keywords = function(){
function kw(type) {return {type: type, style: "js-keyword"};}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {type: "atom", style: "js-atom"};
return {
"if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
"var": kw("var"), "function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
};
}();
var isOperatorChar = /[+\-*&%=<>!?|]/;
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
function nextUntilUnescaped(stream, end) {
var escaped = false, next;
while ((next = stream.next()) != null) {
if (next == end && !escaped)
return false;
escaped = !escaped && next == "\\";
}
return escaped;
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp; content = cont;
return style;
}
function jsTokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'")
return chain(stream, state, jsTokenString(ch));
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
return ret(ch);
else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "js-atom");
}
else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
return ret("number", "js-atom");
}
else if (ch == "/") {
if (stream.eat("*")) {
return chain(stream, state, jsTokenComment);
}
else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "js-comment");
}
else if (state.reAllowed) {
nextUntilUnescaped(stream, "/");
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
return ret("regexp", "js-string");
}
else {
stream.eatWhile(isOperatorChar);
return ret("operator", null, stream.current());
}
}
else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return ret("operator", null, stream.current());
}
else {
stream.eatWhile(/[\w\$_]/);
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
return known ? ret(known.type, known.style, word) :
ret("variable", "js-variable", word);
}
}
function jsTokenString(quote) {
return function(stream, state) {
if (!nextUntilUnescaped(stream, quote))
state.tokenize = jsTokenBase;
return ret("string", "js-string");
};
}
function jsTokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "js-comment");
}
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
function JSLexical(indented, column, type, align, prev, info) {
this.indented = indented;
this.column = column;
this.type = type;
this.prev = prev;
this.info = info;
if (align != null) this.align = align;
}
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
}
function parseJS(state, style, type, content, stream) {
var cc = state.cc;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
while(true) {
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
if (combinator(type, content)) {
while(cc.length && cc[cc.length - 1].lex)
cc.pop()();
if (cx.marked) return cx.marked;
if (type == "variable" && inScope(state, content)) return "js-localvariable";
return style;
}
}
}
// Combinator utils
var cx = {state: null, column: null, marked: null, cc: null};
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function register(varname) {
var state = cx.state;
if (state.context) {
cx.marked = "js-variabledef";
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return;
state.localVars = {name: varname, next: state.localVars};
}
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
function pushcontext() {
if (!cx.state.context) cx.state.localVars = defaultVars;
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
}
function popcontext() {
cx.state.localVars = cx.state.context.vars;
cx.state.context = cx.state.context.prev;
}
function pushlex(type, info) {
var result = function() {
var state = cx.state;
state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
};
result.lex = true;
return result;
}
function poplex() {
var state = cx.state;
if (state.lexical.prev) {
if (state.lexical.type == ")")
state.indented = state.lexical.indented;
state.lexical = state.lexical.prev;
}
}
poplex.lex = true;
function expect(wanted) {
return function expecting(type) {
if (type == wanted) return cont();
else if (wanted == ";") return pass();
else return cont(arguments.callee);
};
}
function statement(type) {
if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
poplex, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
block, poplex, poplex);
if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
if (type == "function") return cont(functiondef);
if (type == "keyword c") return cont(expression);
if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
if (type == "operator") return cont(expression);
if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
return cont();
}
function maybeoperator(type, value) {
if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
if (type == "operator") return cont(expression);
if (type == ";") return;
if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
if (type == ".") return cont(property, maybeoperator);
if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperator, expect(";"), poplex);
}
function property(type) {
if (type == "variable") {cx.marked = "js-property"; return cont();}
}
function objprop(type) {
if (type == "variable") cx.marked = "js-property";
if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
}
function commasep(what, end) {
function proceed(type) {
if (type == ",") return cont(what, proceed);
if (type == end) return cont();
return cont(expect(end));
}
return function commaSeparated(type) {
if (type == end) return cont();
else return pass(what, proceed);
};
}
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function vardef1(type, value) {
if (type == "variable"){register(value); return cont(vardef2);}
return cont();
}
function vardef2(type, value) {
if (value == "=") return cont(expression, vardef2);
if (type == ",") return cont(vardef1);
}
function forspec1(type) {
if (type == "var") return cont(vardef1, forspec2);
if (type == ";") return pass(forspec2);
if (type == "variable") return cont(formaybein);
return pass(forspec2);
}
function formaybein(type, value) {
if (value == "in") return cont(expression);
return cont(maybeoperator, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
if (value == "in") return cont(expression);
return cont(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
if (type == "variable") {register(value); return cont(functiondef);}
if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
}
function funarg(type, value) {
if (type == "variable") {register(value); return cont();}
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: jsTokenBase,
reAllowed: true,
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: null,
context: null,
indented: 0
};
},
token: function(stream, state) {
if (stream.sol()) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
}
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
return parseJS(state, style, type, content, stream);
},
indent: function(state, textAfter) {
if (state.tokenize != jsTokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
type = lexical.type, closing = firstChar == type;
if (type == "vardef") return lexical.indented + 4;
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
else if (lexical.info == "switch" && !closing)
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
electricChars: ":{}"
};
});
CodeMirror.defineMIME("text/javascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});

52
js/codemirror/mode/php/index.html vendored Normal file
View File

@ -0,0 +1,52 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: PHP mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../xml/xml.js"></script>
<link rel="stylesheet" href="../xml/xml.css">
<script src="../javascript/javascript.js"></script>
<link rel="stylesheet" href="../javascript/javascript.css">
<script src="../css/css.js"></script>
<link rel="stylesheet" href="../css/css.css">
<script src="../clike/clike.js"></script>
<link rel="stylesheet" href="../clike/clike.css">
<script src="php.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<link rel="stylesheet" href="../../css/docs.css">
</head>
<body>
<h1>CodeMirror 2: PHP mode</h1>
<form><textarea id="code" name="code">
<?php
function hello($who) {
return "Hello " . $who;
}
?>
<p>The program says <?= hello("World") ?>.</p>
<script>
alert("And here is some JS code"); // also colored
</script>
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
mode: "application/x-httpd-php",
indentUnit: 8,
indentWithTabs: true,
enterMode: "keep",
tabMode: "shift"
});
</script>
<p>Simple HTML/PHP mode based on
the <a href="../clike/">C-like</a> mode. Depends on XML,
JavaScript, CSS, and C-like modes.</p>
<p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code>.</p>
</body>
</html>

83
js/codemirror/mode/php/php.js vendored Normal file
View File

@ -0,0 +1,83 @@
(function() {
function keywords(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}
var phpKeywords =
keywords("abstract and array as break case catch cfunction class clone const continue declare " +
"default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends " +
"final for foreach function global goto if implements interface instanceof namespace " +
"new or private protected public static switch throw try use var while xor");
CodeMirror.defineMode("php", function(config, parserConfig) {
var htmlMode = CodeMirror.getMode(config, "text/html");
var jsMode = CodeMirror.getMode(config, "text/javascript");
var cssMode = CodeMirror.getMode(config, "text/css");
var phpMode = CodeMirror.getMode(config, {name: "clike", keywords: phpKeywords, multiLineStrings: true, $vars: true});
function dispatch(stream, state) { // TODO open PHP inside text/css
if (state.curMode == htmlMode) {
var style = htmlMode.token(stream, state.curState);
if (style == "xml-processing" && /^<\?/.test(stream.current())) {
state.curMode = phpMode;
state.curState = state.php;
state.curClose = /^\?>/;
}
else if (style == "xml-tag" && stream.current() == ">" && state.curState.context) {
if (/^script$/i.test(state.curState.context.tagName)) {
state.curMode = jsMode;
state.curState = jsMode.startState(htmlMode.indent(state.curState, ""));
state.curClose = /^<\/\s*script\s*>/i;
}
else if (/^style$/i.test(state.curState.context.tagName)) {
state.curMode = cssMode;
state.curState = cssMode.startState(htmlMode.indent(state.curState, ""));
state.curClose = /^<\/\s*style\s*>/i;
}
}
return style;
}
else if (stream.match(state.curClose, false)) {
state.curMode = htmlMode;
state.curState = state.html;
state.curClose = null;
return dispatch(stream, state);
}
else return state.curMode.token(stream, state.curState);
}
return {
startState: function() {
var html = htmlMode.startState();
return {html: html,
php: phpMode.startState(),
curMode: htmlMode,
curState: html,
curClose: null}
},
copyState: function(state) {
var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),
php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur;
if (state.curState == html) cur = htmlNew;
else if (state.curState == php) cur = phpNew;
else cur = CodeMirror.copyState(state.curMode, state.curState);
return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, curClose: state.curClose};
},
token: dispatch,
indent: function(state, textAfter) {
if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
(state.curMode == phpMode && /^\?>/.test(textAfter)))
return htmlMode.indent(state.html, textAfter);
return state.curMode.indent(state.curState, textAfter);
},
electricChars: "/{}:"
}
});
})();
CodeMirror.defineMIME("application/x-httpd-php", "php");

63
js/codemirror/mode/plsql/index.html vendored Normal file
View File

@ -0,0 +1,63 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Oracle PL/SQL mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="plsql.js"></script>
<link rel="stylesheet" href="plsql.css">
<link rel="stylesheet" href="../../css/docs.css">
<style>.CodeMirror {border: 2px inset #dee;}</style>
</head>
<body>
<h1>CodeMirror 2: Oracle PL/SQL mode</h1>
<form><textarea id="code" name="code">
-- Oracle PL/SQL Code Demo
/*
based on c-like mode, adapted to PL/SQL by Peter Raganitsch ( http://www.oracle-and-apex.com/ )
April 2011
*/
DECLARE
vIdx NUMBER;
vString VARCHAR2(100);
cText CONSTANT VARCHAR2(100) := 'That''s it! Have fun with CodeMirror 2';
BEGIN
vIdx := 0;
--
FOR rDATA IN
( SELECT *
FROM EMP
ORDER BY EMPNO
)
LOOP
vIdx := vIdx + 1;
vString := rDATA.EMPNO || ' - ' || rDATA.ENAME;
--
UPDATE EMP
SET SAL = SAL * 101/100
WHERE EMPNO = rDATA.EMPNO
;
END LOOP;
--
SYS.DBMS_OUTPUT.Put_Line (cText);
END;
--
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
indentUnit: 4,
mode: "text/x-plsql"
});
</script>
<p>
Simple mode that handles Oracle PL/SQL language (and Oracle SQL, of course).
</p>
<p><strong>MIME type defined:</strong> <code>text/x-plsql</code>
(PLSQL code)
</html>

33
js/codemirror/mode/plsql/plsql.css vendored Normal file
View File

@ -0,0 +1,33 @@
span.plsql-keyword {
color: blue;
}
span.plsql-var {
color: red;
}
span.plsql-comment {
color: #AA7700;
}
span.plsql-string {
color: green;
}
span.plsql-operator {
color: blue;
}
span.plsql-word {
color: black;
}
span.plsql-function {
color: darkorange;
}
span.plsql-sqlplus {
color: darkorange;
}
span.plsql-type {
color: purple;
}
span.plsql-separator {
color: #666666;
}
span.plsql-number {
color: darkcyan;
}

218
js/codemirror/mode/plsql/plsql.js vendored Normal file
View File

@ -0,0 +1,218 @@
CodeMirror.defineMode("plsql", function(config, parserConfig) {
var indentUnit = config.indentUnit,
keywords = parserConfig.keywords,
functions = parserConfig.functions,
types = parserConfig.types,
sqlplus = parserConfig.sqlplus,
multiLineStrings = parserConfig.multiLineStrings;
var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
var type;
function ret(tp, style) {
type = tp;
return style;
}
function tokenBase(stream, state) {
var ch = stream.next();
// start of string?
if (ch == '"' || ch == "'")
return chain(stream, state, tokenString(ch));
// is it one of the special signs []{}().,;? Seperator?
else if (/[\[\]{}\(\),;\.]/.test(ch))
return ret(ch);
// start of a number value?
else if (/\d/.test(ch)) {
stream.eatWhile(/[\w\.]/)
return ret("number", "plsql-number");
}
// multi line comment or simple operator?
else if (ch == "/") {
if (stream.eat("*")) {
return chain(stream, state, tokenComment);
}
else {
stream.eatWhile(isOperatorChar);
return ret("operator", "plsql-operator");
}
}
// single line comment or simple operator?
else if (ch == "-") {
if (stream.eat("-")) {
stream.skipToEnd();
return ret("comment", "plsql-comment");
}
else {
stream.eatWhile(isOperatorChar);
return ret("operator", "plsql-operator");
}
}
// pl/sql variable?
else if (ch == "@" || ch == "$") {
stream.eatWhile(/[\w\d\$_]/);
return ret("word", "plsql-var");
}
// is it a operator?
else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return ret("operator", "plsql-operator");
}
else {
// get the whole word
stream.eatWhile(/[\w\$_]/);
// is it one of the listed keywords?
if (keywords && keywords.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "plsql-keyword");
// is it one of the listed functions?
if (functions && functions.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "plsql-function");
// is it one of the listed types?
if (types && types.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "plsql-type");
// is it one of the listed sqlplus keywords?
if (sqlplus && sqlplus.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "plsql-sqlplus");
// default: just a "word"
return ret("word", "plsql-word");
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote && !escaped) {end = true; break;}
escaped = !escaped && next == "\\";
}
if (end || !(escaped || multiLineStrings))
state.tokenize = tokenBase;
return ret("string", "plsql-string");
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "plsql-comment");
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: tokenBase,
indented: 0,
startOfLine: true
};
},
token: function(stream, state) {
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
return style;
}
};
});
(function() {
function keywords(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}
var cKeywords = "abort accept access add all alter and any array arraylen as asc assert assign at attributes audit " +
"authorization avg " +
"base_table begin between binary_integer body boolean by " +
"case cast char char_base check close cluster clusters colauth column comment commit compress connect " +
"connected constant constraint crash create current currval cursor " +
"data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete " +
"desc digits dispose distinct do drop " +
"else elsif enable end entry escape exception exception_init exchange exclusive exists exit external " +
"fast fetch file for force form from function " +
"generic goto grant group " +
"having " +
"identified if immediate in increment index indexes indicator initial initrans insert interface intersect " +
"into is " +
"key " +
"level library like limited local lock log logging long loop " +
"master maxextents maxtrans member minextents minus mislabel mode modify multiset " +
"new next no noaudit nocompress nologging noparallel not nowait number_base " +
"object of off offline on online only open option or order out " +
"package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior " +
"private privileges procedure public " +
"raise range raw read rebuild record ref references refresh release rename replace resource restrict return " +
"returning reverse revoke rollback row rowid rowlabel rownum rows run " +
"savepoint schema segment select separate session set share snapshot some space split sql start statement " +
"storage subtype successful synonym " +
"tabauth table tables tablespace task terminate then to trigger truncate type " +
"union unique unlimited unrecoverable unusable update use using " +
"validate value values variable view views " +
"when whenever where while with work";
var cFunctions = "abs acos add_months ascii asin atan atan2 average " +
"bfilename " +
"ceil chartorowid chr concat convert cos cosh count " +
"decode deref dual dump dup_val_on_index " +
"empty error exp " +
"false floor found " +
"glb greatest " +
"hextoraw " +
"initcap instr instrb isopen " +
"last_day least lenght lenghtb ln lower lpad ltrim lub " +
"make_ref max min mod months_between " +
"new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower " +
"nls_sort nls_upper nlssort no_data_found notfound null nvl " +
"others " +
"power " +
"rawtohex reftohex round rowcount rowidtochar rpad rtrim " +
"sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate " +
"tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc " +
"uid upper user userenv " +
"variance vsize";
var cTypes = "bfile blob " +
"character clob " +
"dec " +
"float " +
"int integer " +
"mlslabel " +
"natural naturaln nchar nclob number numeric nvarchar2 " +
"real rowtype " +
"signtype smallint string " +
"varchar varchar2";
var cSqlplus = "appinfo arraysize autocommit autoprint autorecovery autotrace " +
"blockterminator break btitle " +
"cmdsep colsep compatibility compute concat copycommit copytypecheck " +
"define describe " +
"echo editfile embedded escape exec execute " +
"feedback flagger flush " +
"heading headsep " +
"instance " +
"linesize lno loboffset logsource long longchunksize " +
"markup " +
"native newpage numformat numwidth " +
"pagesize pause pno " +
"recsep recsepchar release repfooter repheader " +
"serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber " +
"sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix " +
"tab term termout time timing trimout trimspool ttitle " +
"underline " +
"verify version " +
"wrap";
CodeMirror.defineMIME("text/x-plsql", {
name: "plsql",
keywords: keywords(cKeywords),
functions: keywords(cFunctions),
types: keywords(cTypes),
sqlplus: keywords(cSqlplus)
});
}());

21
js/codemirror/mode/python/LICENSE.txt vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2010 Timothy Farrell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

123
js/codemirror/mode/python/index.html vendored Normal file
View File

@ -0,0 +1,123 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Python mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="python.js"></script>
<link rel="stylesheet" href="python.css">
<link rel="stylesheet" href="../../css/docs.css">
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
</head>
<body>
<h1>CodeMirror 2: Python mode</h1>
<div><textarea id="code" name="code">
# Literals
1234
0.0e101
.123
0b01010011100
0o01234567
0x0987654321abcdef
7
2147483647
3L
79228162514264337593543950336L
0x100000000L
79228162514264337593543950336
0xdeadbeef
3.14j
10.j
10j
.001j
1e100j
3.14e-10j
# String Literals
'For\''
"God\""
"""so loved
the world"""
'''that he gave
his only begotten\' '''
'that whosoever believeth \
in him'
''
# Identifiers
__a__
a.b
a.b.c
# Operators
+ - * / % & | ^ ~ < >
== != <= >= <> << >> // **
and or not in is
# Delimiters
() [] {} , : ` = ; @ . # Note that @ and . require the proper context.
+= -= *= /= %= &= |= ^=
//= >>= <<= **=
# Keywords
as assert break class continue def del elif else except
finally for from global if import lambda pass raise
return try while with yield
# Python 2 Keywords (otherwise Identifiers)
exec print
# Python 3 Keywords (otherwise Identifiers)
nonlocal
# Types
bool classmethod complex dict enumerate float frozenset int list object
property reversed set slice staticmethod str super tuple type
# Python 2 Types (otherwise Identifiers)
basestring buffer file long unicode xrange
# Python 3 Types (otherwise Identifiers)
bytearray bytes filter map memoryview open range zip
# Some Example code
import os
from package import ParentClass
@nonsenseDecorator
def doesNothing():
pass
class ExampleClass(ParentClass):
@staticmethod
def example(inputStr):
a = list(inputStr)
a.reverse()
return ''.join(a)
def __init__(self, mixin = 'Hello'):
self.mixin = mixin
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "python",
version: 2,
singleLineStringErrors: false},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift",
matchBrackets: true
});
</script>
<h2>Configuration Options:</h2>
<ul>
<li>version - 2/3 - The version of Python to recognize. Default is 2.</li>
<li>singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.</li>
</ul>
<p><strong>MIME types defined:</strong> <code>text/x-python</code>.</p>
</body>
</html>

23
js/codemirror/mode/python/python.css vendored Normal file
View File

@ -0,0 +1,23 @@
span.py-delimiter,
span.py-special {color: #666666;}
span.py-operator {color: #666666;}
span.py-error {background-color: #660000; color: #FFFFFF;}
span.py-keyword {color: #770088; font-weight: bold;}
span.py-number {color: #228811;}
span.py-identifier,
span.py-func {color: black;}
span.py-type,
span.py-decorator {color: #0000FF;}
span.py-comment {color: #AA7700;}
span.py-string,
span.py-bytes,
span.py-raw,
span.py-unicode {color: #AA2222;}

318
js/codemirror/mode/python/python.js vendored Normal file
View File

@ -0,0 +1,318 @@
CodeMirror.defineMode("python", function(conf) {
var ERRORCLASS = 'py-error';
function wordRegexp(words) {
return new RegExp("^((" + words.join(")|(") + "))\\b");
}
var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
'def', 'del', 'elif', 'else', 'except', 'finally',
'for', 'from', 'global', 'if', 'import',
'lambda', 'pass', 'raise', 'return',
'try', 'while', 'with', 'yield'];
var commontypes = ['bool', 'classmethod', 'complex', 'dict', 'enumerate',
'float', 'frozenset', 'int', 'list', 'object',
'property', 'reversed', 'set', 'slice', 'staticmethod',
'str', 'super', 'tuple', 'type'];
var py2 = {'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
'xrange'],
'keywords': ['exec', 'print']};
var py3 = {'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
'open', 'range', 'zip'],
'keywords': ['nonlocal']};
if (!!conf.mode.version && parseInt(conf.mode.version, 10) === 3) {
commonkeywords = commonkeywords.concat(py3.keywords);
commontypes = commontypes.concat(py3.types);
var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
} else {
commonkeywords = commonkeywords.concat(py2.keywords);
commontypes = commontypes.concat(py2.types);
var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
}
var keywords = wordRegexp(commonkeywords);
var types = wordRegexp(commontypes);
// tokenizers
function tokenBase(stream, state) {
// Handle scope changes
if (stream.sol()) {
var scopeOffset = state.scopes[0].offset;
if (stream.eatSpace()) {
var lineOffset = stream.indentation();
if (lineOffset > scopeOffset) {
return 'py-indent';
} else if (lineOffset < scopeOffset) {
return 'py-dedent';
}
return 'whitespace';
} else {
if (scopeOffset > 0) {
dedent(stream, state);
}
}
}
if (stream.eatSpace()) {
return 'py-space';
}
var ch = stream.peek();
// Handle Comments
if (ch === '#') {
stream.skipToEnd();
return 'py-comment';
}
// Handle Number Literals
if (stream.match(/^[0-9\.]/, false)) {
var floatLiteral = false;
// Floats
if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
if (stream.match(/^\.\d+/)) { floatLiteral = true; }
if (floatLiteral) {
// Float literals may be "imaginary"
stream.eat(/J/i);
return 'py-literal';
}
// Integers
var intLiteral = false;
// Hex
if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
// Binary
if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
// Octal
if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
// Decimal
if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
// Decimal literals may be "imaginary"
stream.eat(/J/i);
// TODO - Can you have imaginary longs?
intLiteral = true;
}
// Zero by itself with no other piece of number.
if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
if (intLiteral) {
// Integer literals may be "long"
stream.eat(/L/i);
return 'py-literal';
}
}
// Handle Strings
if (stream.match(stringPrefixes)) {
state.tokenize = tokenStringFactory(stream.current());
return state.tokenize(stream, state);
}
// Handle operators and Delimiters
if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
return 'py-delimiter';
}
if (stream.match(doubleOperators)
|| stream.match(singleOperators)
|| stream.match(wordOperators)) {
return 'py-operator';
}
if (stream.match(singleDelimiters)) {
return 'py-delimiter';
}
if (stream.match(types)) {
return 'py-type';
}
if (stream.match(keywords)) {
return 'py-keyword';
}
if (stream.match(identifiers)) {
return 'py-identifier';
}
// Handle non-detected items
stream.next();
return ERRORCLASS;
}
function tokenStringFactory(delimiter) {
while ('rub'.indexOf(delimiter[0].toLowerCase()) >= 0) {
delimiter = delimiter.substr(1);
}
var delim_re = new RegExp(delimiter);
var singleline = delimiter.length == 1;
var OUTCLASS = 'py-string';
return function tokenString(stream, state) {
while (!stream.eol()) {
stream.eatWhile(/[^'"\\]/);
if (stream.eat('\\')) {
stream.next();
if (singleline && stream.eol()) {
return OUTCLASS;
}
} else if (stream.match(delim_re)) {
state.tokenize = tokenBase;
return OUTCLASS;
} else {
stream.eat(/['"]/);
}
}
if (singleline) {
if (conf.mode.singleLineStringErrors) {
OUTCLASS = ERRORCLASS
} else {
state.tokenize = tokenBase;
}
}
return OUTCLASS;
};
}
function indent(stream, state, type) {
type = type || 'py';
var indentUnit = 0;
if (type === 'py') {
for (var i = 0; i < state.scopes.length; ++i) {
if (state.scopes[i].type === 'py') {
indentUnit = state.scopes[i].offset + conf.indentUnit;
break;
}
}
} else {
indentUnit = stream.column() + stream.current().length;
}
state.scopes.unshift({
offset: indentUnit,
type: type
});
}
function dedent(stream, state) {
if (state.scopes.length == 1) return;
if (state.scopes[0].type === 'py') {
var _indent = stream.indentation();
var _indent_index = -1;
for (var i = 0; i < state.scopes.length; ++i) {
if (_indent === state.scopes[i].offset) {
_indent_index = i;
break;
}
}
if (_indent_index === -1) {
return true;
}
while (state.scopes[0].offset !== _indent) {
state.scopes.shift();
}
return false
} else {
state.scopes.shift();
return false;
}
}
function tokenLexer(stream, state) {
var style = state.tokenize(stream, state);
var current = stream.current();
// Handle '.' connected identifiers
if (current === '.') {
style = state.tokenize(stream, state);
current = stream.current();
if (style === 'py-identifier') {
return 'py-identifier';
} else {
return ERRORCLASS;
}
}
// Handle decorators
if (current === '@') {
style = state.tokenize(stream, state);
current = stream.current();
if (style === 'py-identifier'
|| current === '@staticmethod'
|| current === '@classmethod') {
return 'py-decorator';
} else {
return ERRORCLASS;
}
}
// Handle scope changes.
if (current === 'pass' || current === 'return') {
state.dedent += 1;
}
if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
|| style === 'py-indent') {
indent(stream, state);
}
var delimiter_index = '[({'.indexOf(current);
if (delimiter_index !== -1) {
indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
}
if (style === 'py-dedent') {
if (dedent(stream, state)) {
return ERRORCLASS;
}
}
delimiter_index = '])}'.indexOf(current);
if (delimiter_index !== -1) {
if (dedent(stream, state)) {
return ERRORCLASS;
}
}
if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
if (state.scopes.length > 1) state.scopes.shift();
state.dedent -= 1;
}
return style;
}
var external = {
startState: function(basecolumn) {
return {
tokenize: tokenBase,
scopes: [{offset:basecolumn || 0, type:'py'}],
lastToken: null,
lambda: false,
dedent: 0
};
},
token: function(stream, state) {
var style = tokenLexer(stream, state);
state.lastToken = {style:style, content: stream.current()};
if (stream.eol() && stream.lambda) {
state.lambda = false;
}
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase) {
return 0;
}
return state.scopes[0].offset;
}
};
return external;
});
CodeMirror.defineMIME("text/x-python", "python");

526
js/codemirror/mode/rst/index.html vendored Normal file
View File

@ -0,0 +1,526 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: reStructuredText mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="rst.js"></script>
<link rel="stylesheet" href="rst.css">
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<link rel="stylesheet" href="../../css/docs.css">
</head>
<body>
<h1>CodeMirror 2: reStructuredText mode</h1>
<form><textarea id="code" name="code">
.. This is an excerpt from Sphinx documentation: http://sphinx.pocoo.org/_sources/rest.txt
.. highlightlang:: rest
.. _rst-primer:
reStructuredText Primer
=======================
This section is a brief introduction to reStructuredText (reST) concepts and
syntax, intended to provide authors with enough information to author documents
productively. Since reST was designed to be a simple, unobtrusive markup
language, this will not take too long.
.. seealso::
The authoritative `reStructuredText User Documentation
&lt;http://docutils.sourceforge.net/rst.html&gt;`_. The "ref" links in this
document link to the description of the individual constructs in the reST
reference.
Paragraphs
----------
The paragraph (:duref:`ref &lt;paragraphs&gt;`) is the most basic block in a reST
document. Paragraphs are simply chunks of text separated by one or more blank
lines. As in Python, indentation is significant in reST, so all lines of the
same paragraph must be left-aligned to the same level of indentation.
.. _inlinemarkup:
Inline markup
-------------
The standard reST inline markup is quite simple: use
* one asterisk: ``*text*`` for emphasis (italics),
* two asterisks: ``**text**`` for strong emphasis (boldface), and
* backquotes: ````text```` for code samples.
If asterisks or backquotes appear in running text and could be confused with
inline markup delimiters, they have to be escaped with a backslash.
Be aware of some restrictions of this markup:
* it may not be nested,
* content may not start or end with whitespace: ``* text*`` is wrong,
* it must be separated from surrounding text by non-word characters. Use a
backslash escaped space to work around that: ``thisis\ *one*\ word``.
These restrictions may be lifted in future versions of the docutils.
reST also allows for custom "interpreted text roles"', which signify that the
enclosed text should be interpreted in a specific way. Sphinx uses this to
provide semantic markup and cross-referencing of identifiers, as described in
the appropriate section. The general syntax is ``:rolename:`content```.
Standard reST provides the following roles:
* :durole:`emphasis` -- alternate spelling for ``*emphasis*``
* :durole:`strong` -- alternate spelling for ``**strong**``
* :durole:`literal` -- alternate spelling for ````literal````
* :durole:`subscript` -- subscript text
* :durole:`superscript` -- superscript text
* :durole:`title-reference` -- for titles of books, periodicals, and other
materials
See :ref:`inline-markup` for roles added by Sphinx.
Lists and Quote-like blocks
---------------------------
List markup (:duref:`ref &lt;bullet-lists&gt;`) is natural: just place an asterisk at
the start of a paragraph and indent properly. The same goes for numbered lists;
they can also be autonumbered using a ``#`` sign::
* This is a bulleted list.
* It has two items, the second
item uses two lines.
1. This is a numbered list.
2. It has two items too.
#. This is a numbered list.
#. It has two items too.
Nested lists are possible, but be aware that they must be separated from the
parent list items by blank lines::
* this is
* a list
* with a nested list
* and some subitems
* and here the parent list continues
Definition lists (:duref:`ref &lt;definition-lists&gt;`) are created as follows::
term (up to a line of text)
Definition of the term, which must be indented
and can even consist of multiple paragraphs
next term
Description.
Note that the term cannot have more than one line of text.
Quoted paragraphs (:duref:`ref &lt;block-quotes&gt;`) are created by just indenting
them more than the surrounding paragraphs.
Line blocks (:duref:`ref &lt;line-blocks&gt;`) are a way of preserving line breaks::
| These lines are
| broken exactly like in
| the source file.
There are also several more special blocks available:
* field lists (:duref:`ref &lt;field-lists&gt;`)
* option lists (:duref:`ref &lt;option-lists&gt;`)
* quoted literal blocks (:duref:`ref &lt;quoted-literal-blocks&gt;`)
* doctest blocks (:duref:`ref &lt;doctest-blocks&gt;`)
Source Code
-----------
Literal code blocks (:duref:`ref &lt;literal-blocks&gt;`) are introduced by ending a
paragraph with the special marker ``::``. The literal block must be indented
(and, like all paragraphs, separated from the surrounding ones by blank lines)::
This is a normal text paragraph. The next paragraph is a code sample::
It is not processed in any way, except
that the indentation is removed.
It can span multiple lines.
This is a normal text paragraph again.
The handling of the ``::`` marker is smart:
* If it occurs as a paragraph of its own, that paragraph is completely left
out of the document.
* If it is preceded by whitespace, the marker is removed.
* If it is preceded by non-whitespace, the marker is replaced by a single
colon.
That way, the second sentence in the above example's first paragraph would be
rendered as "The next paragraph is a code sample:".
.. _rst-tables:
Tables
------
Two forms of tables are supported. For *grid tables* (:duref:`ref
&lt;grid-tables&gt;`), you have to "paint" the cell grid yourself. They look like
this::
+------------------------+------------+----------+----------+
| Header row, column 1 | Header 2 | Header 3 | Header 4 |
| (header rows optional) | | | |
+========================+============+==========+==========+
| body row 1, column 1 | column 2 | column 3 | column 4 |
+------------------------+------------+----------+----------+
| body row 2 | ... | ... | |
+------------------------+------------+----------+----------+
*Simple tables* (:duref:`ref &lt;simple-tables&gt;`) are easier to write, but
limited: they must contain more than one row, and the first column cannot
contain multiple lines. They look like this::
===== ===== =======
A B A and B
===== ===== =======
False False False
True False False
False True False
True True True
===== ===== =======
Hyperlinks
----------
External links
^^^^^^^^^^^^^^
Use ```Link text &lt;http://example.com/&gt;`_`` for inline web links. If the link
text should be the web address, you don't need special markup at all, the parser
finds links and mail addresses in ordinary text.
You can also separate the link and the target definition (:duref:`ref
&lt;hyperlink-targets&gt;`), like this::
This is a paragraph that contains `a link`_.
.. _a link: http://example.com/
Internal links
^^^^^^^^^^^^^^
Internal linking is done via a special reST role provided by Sphinx, see the
section on specific markup, :ref:`ref-role`.
Sections
--------
Section headers (:duref:`ref &lt;sections&gt;`) are created by underlining (and
optionally overlining) the section title with a punctuation character, at least
as long as the text::
=================
This is a heading
=================
Normally, there are no heading levels assigned to certain characters as the
structure is determined from the succession of headings. However, for the
Python documentation, this convention is used which you may follow:
* ``#`` with overline, for parts
* ``*`` with overline, for chapters
* ``=``, for sections
* ``-``, for subsections
* ``^``, for subsubsections
* ``"``, for paragraphs
Of course, you are free to use your own marker characters (see the reST
documentation), and use a deeper nesting level, but keep in mind that most
target formats (HTML, LaTeX) have a limited supported nesting depth.
Explicit Markup
---------------
"Explicit markup" (:duref:`ref &lt;explicit-markup-blocks&gt;`) is used in reST for
most constructs that need special handling, such as footnotes,
specially-highlighted paragraphs, comments, and generic directives.
An explicit markup block begins with a line starting with ``..`` followed by
whitespace and is terminated by the next paragraph at the same level of
indentation. (There needs to be a blank line between explicit markup and normal
paragraphs. This may all sound a bit complicated, but it is intuitive enough
when you write it.)
.. _directives:
Directives
----------
A directive (:duref:`ref &lt;directives&gt;`) is a generic block of explicit markup.
Besides roles, it is one of the extension mechanisms of reST, and Sphinx makes
heavy use of it.
Docutils supports the following directives:
* Admonitions: :dudir:`attention`, :dudir:`caution`, :dudir:`danger`,
:dudir:`error`, :dudir:`hint`, :dudir:`important`, :dudir:`note`,
:dudir:`tip`, :dudir:`warning` and the generic :dudir:`admonition`.
(Most themes style only "note" and "warning" specially.)
* Images:
- :dudir:`image` (see also Images_ below)
- :dudir:`figure` (an image with caption and optional legend)
* Additional body elements:
- :dudir:`contents` (a local, i.e. for the current file only, table of
contents)
- :dudir:`container` (a container with a custom class, useful to generate an
outer ``&lt;div&gt;`` in HTML)
- :dudir:`rubric` (a heading without relation to the document sectioning)
- :dudir:`topic`, :dudir:`sidebar` (special highlighted body elements)
- :dudir:`parsed-literal` (literal block that supports inline markup)
- :dudir:`epigraph` (a block quote with optional attribution line)
- :dudir:`highlights`, :dudir:`pull-quote` (block quotes with their own
class attribute)
- :dudir:`compound` (a compound paragraph)
* Special tables:
- :dudir:`table` (a table with title)
- :dudir:`csv-table` (a table generated from comma-separated values)
- :dudir:`list-table` (a table generated from a list of lists)
* Special directives:
- :dudir:`raw` (include raw target-format markup)
- :dudir:`include` (include reStructuredText from another file)
-- in Sphinx, when given an absolute include file path, this directive takes
it as relative to the source directory
- :dudir:`class` (assign a class attribute to the next element) [1]_
* HTML specifics:
- :dudir:`meta` (generation of HTML ``&lt;meta&gt;`` tags)
- :dudir:`title` (override document title)
* Influencing markup:
- :dudir:`default-role` (set a new default role)
- :dudir:`role` (create a new role)
Since these are only per-file, better use Sphinx' facilities for setting the
:confval:`default_role`.
Do *not* use the directives :dudir:`sectnum`, :dudir:`header` and
:dudir:`footer`.
Directives added by Sphinx are described in :ref:`sphinxmarkup`.
Basically, a directive consists of a name, arguments, options and content. (Keep
this terminology in mind, it is used in the next chapter describing custom
directives.) Looking at this example, ::
.. function:: foo(x)
foo(y, z)
:module: some.module.name
Return a line of text input from the user.
``function`` is the directive name. It is given two arguments here, the
remainder of the first line and the second line, as well as one option
``module`` (as you can see, options are given in the lines immediately following
the arguments and indicated by the colons). Options must be indented to the
same level as the directive content.
The directive content follows after a blank line and is indented relative to the
directive start.
Images
------
reST supports an image directive (:dudir:`ref &lt;image&gt;`), used like so::
.. image:: gnu.png
(options)
When used within Sphinx, the file name given (here ``gnu.png``) must either be
relative to the source file, or absolute which means that they are relative to
the top source directory. For example, the file ``sketch/spam.rst`` could refer
to the image ``images/spam.png`` as ``../images/spam.png`` or
``/images/spam.png``.
Sphinx will automatically copy image files over to a subdirectory of the output
directory on building (e.g. the ``_static`` directory for HTML output.)
Interpretation of image size options (``width`` and ``height``) is as follows:
if the size has no unit or the unit is pixels, the given size will only be
respected for output channels that support pixels (i.e. not in LaTeX output).
Other units (like ``pt`` for points) will be used for HTML and LaTeX output.
Sphinx extends the standard docutils behavior by allowing an asterisk for the
extension::
.. image:: gnu.*
Sphinx then searches for all images matching the provided pattern and determines
their type. Each builder then chooses the best image out of these candidates.
For instance, if the file name ``gnu.*`` was given and two files :file:`gnu.pdf`
and :file:`gnu.png` existed in the source tree, the LaTeX builder would choose
the former, while the HTML builder would prefer the latter.
.. versionchanged:: 0.4
Added the support for file names ending in an asterisk.
.. versionchanged:: 0.6
Image paths can now be absolute.
Footnotes
---------
For footnotes (:duref:`ref &lt;footnotes&gt;`), use ``[#name]_`` to mark the footnote
location, and add the footnote body at the bottom of the document after a
"Footnotes" rubric heading, like so::
Lorem ipsum [#f1]_ dolor sit amet ... [#f2]_
.. rubric:: Footnotes
.. [#f1] Text of the first footnote.
.. [#f2] Text of the second footnote.
You can also explicitly number the footnotes (``[1]_``) or use auto-numbered
footnotes without names (``[#]_``).
Citations
---------
Standard reST citations (:duref:`ref &lt;citations&gt;`) are supported, with the
additional feature that they are "global", i.e. all citations can be referenced
from all files. Use them like so::
Lorem ipsum [Ref]_ dolor sit amet.
.. [Ref] Book or article reference, URL or whatever.
Citation usage is similar to footnote usage, but with a label that is not
numeric or begins with ``#``.
Substitutions
-------------
reST supports "substitutions" (:duref:`ref &lt;substitution-definitions&gt;`), which
are pieces of text and/or markup referred to in the text by ``|name|``. They
are defined like footnotes with explicit markup blocks, like this::
.. |name| replace:: replacement *text*
or this::
.. |caution| image:: warning.png
:alt: Warning!
See the :duref:`reST reference for substitutions &lt;substitution-definitions&gt;`
for details.
If you want to use some substitutions for all documents, put them into
:confval:`rst_prolog` or put them into a separate file and include it into all
documents you want to use them in, using the :rst:dir:`include` directive. (Be
sure to give the include file a file name extension differing from that of other
source files, to avoid Sphinx finding it as a standalone document.)
Sphinx defines some default substitutions, see :ref:`default-substitutions`.
Comments
--------
Every explicit markup block which isn't a valid markup construct (like the
footnotes above) is regarded as a comment (:duref:`ref &lt;comments&gt;`). For
example::
.. This is a comment.
You can indent text after a comment start to form multiline comments::
..
This whole indented block
is a comment.
Still in the comment.
Source encoding
---------------
Since the easiest way to include special characters like em dashes or copyright
signs in reST is to directly write them as Unicode characters, one has to
specify an encoding. Sphinx assumes source files to be encoded in UTF-8 by
default; you can change this with the :confval:`source_encoding` config value.
Gotchas
-------
There are some problems one commonly runs into while authoring reST documents:
* **Separation of inline markup:** As said above, inline markup spans must be
separated from the surrounding text by non-word characters, you have to use a
backslash-escaped space to get around that. See `the reference
&lt;http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup&gt;`_
for the details.
* **No nested inline markup:** Something like ``*see :func:`foo`*`` is not
possible.
.. rubric:: Footnotes
.. [1] When the default domain contains a :rst:dir:`class` directive, this directive
will be shadowed. Therefore, Sphinx re-exports it as :rst:dir:`rst-class`.
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
});
</script>
<p>The reStructuredText mode supports one configuration parameter:</p>
<dl>
<dt><code>verbatim (string)</code></dt>
<dd>A name or MIME type of a mode that will be used for highlighting
verbatim blocks. By default, reStructuredText mode uses uniform color
for whole block of verbatim text if no mode is given.</dd>
</dl>
<p>If <code>python</code> mode is available (not a part of CodeMirror 2 yet),
it will be used for highlighting blocks containing Python/IPython terminal
sessions (blocks starting with <code>&gt;&gt;&gt;</code> (for Python) or
<code>In [num]:</code> (for IPython).
<p><strong>MIME types defined:</strong> <code>text/x-rst</code>.</p>
</body>
</html>

77
js/codemirror/mode/rst/rst.css vendored Normal file
View File

@ -0,0 +1,77 @@
span.rst-emphasis {
font-style: italic;
}
span.rst-strong {
font-weight: bold;
}
span.rst-interpreted {
color: #33cc66;
}
span.rst-inline {
color: #3399cc;
}
span.rst-role {
color: #666699;
}
span.rst-list {
color: #cc0099;
font-weight: bold;
}
span.rst-body {
color: #6699cc;
}
span.rst-verbatim {
color: #3366ff;
}
span.rst-comment {
color: #aa7700;
}
span.rst-directive {
font-weight: bold;
color: #3399ff;
}
span.rst-hyperlink {
font-weight: bold;
color: #3366ff;
}
span.rst-footnote {
font-weight: bold;
color: #3333ff;
}
span.rst-citation {
font-weight: bold;
color: #3300ff;
}
span.rst-replacement {
color: #9933cc;
}
span.rst-section {
font-weight: bold;
color: #cc0099;
}
span.rst-directive-marker {
font-weight: bold;
color: #3399ff;
}
span.rst-verbatim-marker {
font-weight: bold;
color: #9900ff;
}

335
js/codemirror/mode/rst/rst.js vendored Normal file
View File

@ -0,0 +1,335 @@
CodeMirror.defineMode('rst', function(config, options) {
function setState(state, fn, ctx) {
state.fn = fn;
setCtx(state, ctx);
}
function setCtx(state, ctx) {
state.ctx = ctx || {};
}
function setNormal(state, ch) {
if (ch && (typeof ch !== 'string')) {
var str = ch.current();
ch = str[str.length-1];
}
setState(state, normal, {back: ch});
}
function hasMode(mode) {
if (mode) {
var modes = CodeMirror.listModes();
for (var i in modes) {
if (modes[i] == mode) {
return true;
}
}
}
return false;
}
function getMode(mode) {
if (hasMode(mode)) {
return CodeMirror.getMode(config, mode);
} else {
return null;
}
}
var verbatimMode = getMode(options.verbatim);
var pythonMode = getMode('python');
var reSection = /^[!"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]/;
var reDirective = /^\s*\w([-:.\w]*\w)?::(\s|$)/;
var reHyperlink = /^\s*_[\w-]+:(\s|$)/;
var reFootnote = /^\s*\[(\d+|#)\](\s|$)/;
var reCitation = /^\s*\[[A-Za-z][\w-]*\](\s|$)/;
var reFootnoteRef = /^\[(\d+|#)\]_/;
var reCitationRef = /^\[[A-Za-z][\w-]*\]_/;
var reDirectiveMarker = /^\.\.(\s|$)/;
var reVerbatimMarker = /^::\s*$/;
var rePreInline = /^[-\s"([{</:]/;
var rePostInline = /^[-\s`'")\]}>/:.,;!?\\_]/;
var reEnumeratedList = /^\s*((\d+|[A-Za-z#])[.)]|\((\d+|[A-Z-a-z#])\))\s/;
var reBulletedList = /^\s*[-\+\*]\s/;
var reExamples = /^\s+(>>>|In \[\d+\]:)\s/;
function normal(stream, state) {
var ch, sol, i;
if (stream.eat(/\\/)) {
ch = stream.next();
setNormal(state, ch);
return null;
}
sol = stream.sol();
if (sol && (ch = stream.eat(reSection))) {
for (i = 0; stream.eat(ch); i++);
if (i >= 3 && stream.match(/^\s*$/)) {
setNormal(state, null);
return 'rst-section';
} else {
stream.backUp(i + 1);
}
}
if (sol && stream.match(reDirectiveMarker)) {
if (!stream.eol()) {
setState(state, directive);
}
return 'rst-directive-marker';
}
if (stream.match(reVerbatimMarker)) {
if (!verbatimMode) {
setState(state, verbatim);
} else {
var mode = verbatimMode;
setState(state, verbatim, {
mode: mode,
local: mode.startState()
});
}
return 'rst-verbatim-marker';
}
if (sol && stream.match(reExamples, false)) {
if (!pythonMode) {
setState(state, verbatim);
return 'rst-verbatim-marker';
} else {
var mode = pythonMode;
setState(state, verbatim, {
mode: mode,
local: mode.startState()
});
return null;
}
}
if (sol && (stream.match(reEnumeratedList) ||
stream.match(reBulletedList))) {
setNormal(state, stream);
return 'rst-list';
}
function testBackward(re) {
return sol || !state.ctx.back || re.test(state.ctx.back);
}
function testForward(re) {
return stream.eol() || stream.match(re, false);
}
function testInline(re) {
return stream.match(re) && testBackward(/\W/) && testForward(/\W/);
}
if (testInline(reFootnoteRef)) {
setNormal(state, stream);
return 'rst-footnote';
}
if (testInline(reCitationRef)) {
setNormal(state, stream);
return 'rst-citation';
}
ch = stream.next();
if (testBackward(rePreInline)) {
if ((ch === ':' || ch === '|') && stream.eat(/\S/)) {
var token;
if (ch === ':') {
token = 'rst-role';
} else {
token = 'rst-replacement';
}
setState(state, inline, {
ch: ch,
wide: false,
prev: null,
token: token
});
return token;
}
if (ch === '*' || ch === '`') {
var orig = ch,
wide = false;
ch = stream.next();
if (ch == orig) {
wide = true;
ch = stream.next();
}
if (ch && !/\s/.test(ch)) {
var token;
if (orig === '*') {
token = wide ? 'rst-strong' : 'rst-emphasis';
} else {
token = wide ? 'rst-inline' : 'rst-interpreted';
}
setState(state, inline, {
ch: orig, // inline() has to know what to search for
wide: wide, // are we looking for `ch` or `chch`
prev: null, // terminator must not be preceeded with whitespace
token: token // I don't want to recompute this all the time
});
return token;
}
}
}
setNormal(state, ch);
return null;
}
function inline(stream, state) {
var ch = stream.next(),
token = state.ctx.token;
function finish(ch) {
state.ctx.prev = ch;
return token;
}
if (ch != state.ctx.ch) {
return finish(ch);
}
if (/\s/.test(state.ctx.prev)) {
return finish(ch);
}
if (state.ctx.wide) {
ch = stream.next();
if (ch != state.ctx.ch) {
return finish(ch);
}
}
if (!stream.eol() && !rePostInline.test(stream.peek())) {
if (state.ctx.wide) {
stream.backUp(1);
}
return finish(ch);
}
setState(state, normal);
setNormal(state, ch);
return token;
}
function directive(stream, state) {
var token = null;
if (stream.match(reDirective)) {
token = 'rst-directive';
} else if (stream.match(reHyperlink)) {
token = 'rst-hyperlink';
} else if (stream.match(reFootnote)) {
token = 'rst-footnote';
} else if (stream.match(reCitation)) {
token = 'rst-citation';
} else {
stream.eatSpace();
if (stream.eol()) {
setNormal(state, stream);
return null;
} else {
stream.skipToEnd();
setState(state, comment);
return 'rst-comment';
}
}
setState(state, body, {start: true});
return token;
}
function body(stream, state) {
var token = 'rst-body';
if (!state.ctx.start || stream.sol()) {
return block(stream, state, token);
}
stream.skipToEnd();
setCtx(state);
return token;
}
function comment(stream, state) {
return block(stream, state, 'rst-comment');
}
function verbatim(stream, state) {
if (!verbatimMode) {
return block(stream, state, 'rst-verbatim');
} else {
if (stream.sol()) {
if (!stream.eatSpace()) {
setNormal(state, stream);
}
return null;
}
return verbatimMode.token(stream, state.ctx.local);
}
}
function block(stream, state, token) {
if (stream.eol() || stream.eatSpace()) {
stream.skipToEnd();
return token;
} else {
setNormal(state, stream);
return null;
}
}
return {
startState: function() {
return {fn: normal, ctx: {}};
},
copyState: function(state) {
return {fn: state.fn, ctx: state.ctx};
},
token: function(stream, state) {
var token = state.fn(stream, state);
return token;
}
};
});
CodeMirror.defineMIME("text/x-rst", "rst");

56
js/codemirror/mode/smalltalk/index.html vendored Normal file
View File

@ -0,0 +1,56 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Smalltalk mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="smalltalk.js"></script>
<link rel="stylesheet" href="smalltalk.css">
<link rel="stylesheet" href="../../css/docs.css">
<style>
.CodeMirror {border: 2px solid #dee; border-right-width: 10px;}
.CodeMirror-gutter {border: none; background: #dee;}
.CodeMirror-gutter pre {color: white; font-weight: bold;}
</style>
</head>
<body>
<h1>CodeMirror 2: Smalltalk mode</h1>
<form><textarea id="code" name="code">
"
This is a test of the Smalltalk code
"
Seaside.WAComponent subclass: #MyCounter [
| count |
MyCounter class &gt;&gt; canBeRoot [ ^true ]
initialize [
super initialize.
count := 0.
]
states [ ^{ self } ]
renderContentOn: html [
html heading: count.
html anchor callback: [ count := count + 1 ]; with: '++'.
html space.
html anchor callback: [ count := count - 1 ]; with: '--'.
]
]
MyCounter registerAsApplication: 'mycounter'
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-stsrc",
indentUnit: 4
});
</script>
<p>Simple Smalltalk mode.</p>
<p><strong>MIME types defined:</strong> <code>text/x-stsrc</code>.</p>
</body>
</html>

View File

@ -0,0 +1,5 @@
span.st-keyword {color: #90b;}
span.st-number {color: #291;}
span.st-comment {color: #a70;}
span.st-string {color: #a22;}
span.st-var {color: #22b;}

View File

@ -0,0 +1,122 @@
CodeMirror.defineMode("smalltalk", function(config, parserConfig) {
var keywords = {"true": 1, "false": 1, nil: 1, self: 1, "super": 1, thisContext: 1};
var indentUnit = config.indentUnit;
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
var type;
function ret(tp, style) {
type = tp;
return style;
}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"')
return chain(stream, state, tokenComment(ch));
else if (ch == "'")
return chain(stream, state, tokenString(ch));
else if (ch == "#") {
stream.eatWhile(/[\w\$_]/);
return ret("string", "st-string");
}
else if (/\d/.test(ch)) {
stream.eatWhile(/[\w\.]/)
return ret("number", "st-number");
}
else if (/[\[\]()]/.test(ch)) {
return ret(ch, null);
}
else {
stream.eatWhile(/[\w\$_]/);
if (keywords && keywords.propertyIsEnumerable(stream.current())) return ret("keyword", "st-keyword");
return ret("word", "st-word");
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote && !escaped) {end = true; break;}
escaped = !escaped && next == "\\";
}
if (end || !(escaped))
state.tokenize = tokenBase;
return ret("string", "st-string");
};
}
function tokenComment(quote) {
return function(stream, state) {
var next, end = false;
while ((next = stream.next()) != null) {
if (next == quote) {end = true; break;}
}
if (end)
state.tokenize = tokenBase;
return ret("comment", "st-comment");
};
}
function Context(indented, column, type, align, prev) {
this.indented = indented;
this.column = column;
this.type = type;
this.align = align;
this.prev = prev;
}
function pushContext(state, col, type) {
return state.context = new Context(state.indented, col, type, null, state.context);
}
function popContext(state) {
return state.context = state.context.prev;
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: tokenBase,
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
indented: 0,
startOfLine: true
};
},
token: function(stream, state) {
var ctx = state.context;
if (stream.sol()) {
if (ctx.align == null) ctx.align = false;
state.indented = stream.indentation();
state.startOfLine = true;
}
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
if (ctx.align == null) ctx.align = true;
if (type == "[") pushContext(state, stream.column(), "]");
else if (type == "(") pushContext(state, stream.column(), ")");
else if (type == ctx.type) popContext(state);
state.startOfLine = false;
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type;
if (ctx.align) return ctx.column + (closing ? 0 : 1);
else return ctx.indented + (closing ? 0 : indentUnit);
},
electricChars: "]"
};
});
CodeMirror.defineMIME("text/x-stsrc", {name: "smalltalk"});

96
js/codemirror/mode/stex/index.html vendored Normal file
View File

@ -0,0 +1,96 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: sTeX mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="stex.js"></script>
<link rel="stylesheet" href="stex.css">
<style>.CodeMirror {background: #f8f8f8;}</style>
<link rel="stylesheet" href="../../css/docs.css">
</head>
<body>
<h1>CodeMirror 2: sTeX mode</h1>
<form><textarea id="code" name="code">
\begin{module}[id=bbt-size]
\importmodule[balanced-binary-trees]{balanced-binary-trees}
\importmodule[\KWARCslides{dmath/en/cardinality}]{cardinality}
\begin{frame}
\frametitle{Size Lemma for Balanced Trees}
\begin{itemize}
\item
\begin{assertion}[id=size-lemma,type=lemma]
Let $G=\tup{V,E}$ be a \termref[cd=binary-trees]{balanced binary tree}
of \termref[cd=graph-depth,name=vertex-depth]{depth}$n>i$, then the set
$\defeq{\livar{V}i}{\setst{\inset{v}{V}}{\gdepth{v} = i}}$ of
\termref[cd=graphs-intro,name=node]{nodes} at
\termref[cd=graph-depth,name=vertex-depth]{depth} $i$ has
\termref[cd=cardinality,name=cardinality]{cardinality} $\power2i$.
\end{assertion}
\item
\begin{sproof}[id=size-lemma-pf,proofend=,for=size-lemma]{via induction over the depth $i$.}
\begin{spfcases}{We have to consider two cases}
\begin{spfcase}{$i=0$}
\begin{spfstep}[display=flow]
then $\livar{V}i=\set{\livar{v}r}$, where $\livar{v}r$ is the root, so
$\eq{\card{\livar{V}0},\card{\set{\livar{v}r}},1,\power20}$.
\end{spfstep}
\end{spfcase}
\begin{spfcase}{$i>0$}
\begin{spfstep}[display=flow]
then $\livar{V}{i-1}$ contains $\power2{i-1}$ vertexes
\begin{justification}[method=byIH](IH)\end{justification}
\end{spfstep}
\begin{spfstep}
By the \begin{justification}[method=byDef]definition of a binary
tree\end{justification}, each $\inset{v}{\livar{V}{i-1}}$ is a leaf or has
two children that are at depth $i$.
\end{spfstep}
\begin{spfstep}
As $G$ is \termref[cd=balanced-binary-trees,name=balanced-binary-tree]{balanced} and $\gdepth{G}=n>i$, $\livar{V}{i-1}$ cannot contain
leaves.
\end{spfstep}
\begin{spfstep}[type=conclusion]
Thus $\eq{\card{\livar{V}i},{\atimes[cdot]{2,\card{\livar{V}{i-1}}}},{\atimes[cdot]{2,\power2{i-1}}},\power2i}$.
\end{spfstep}
\end{spfcase}
\end{spfcases}
\end{sproof}
\item
\begin{assertion}[id=fbbt,type=corollary]
A fully balanced tree of depth $d$ has $\power2{d+1}-1$ nodes.
\end{assertion}
\item
\begin{sproof}[for=fbbt,id=fbbt-pf]{}
\begin{spfstep}
Let $\defeq{G}{\tup{V,E}}$ be a fully balanced tree
\end{spfstep}
\begin{spfstep}
Then $\card{V}=\Sumfromto{i}1d{\power2i}= \power2{d+1}-1$.
\end{spfstep}
\end{sproof}
\end{itemize}
\end{frame}
\begin{note}
\begin{omtext}[type=conclusion,for=binary-tree]
This shows that balanced binary trees grow in breadth very quickly, a consequence of
this is that they are very shallow (and this compute very fast), which is the essence of
the next result.
\end{omtext}
\end{note}
\end{module}
%%% Local Variables:
%%% mode: LaTeX
%%% TeX-master: "all"
%%% End: \end{document}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script>
<p><strong>MIME types defined:</strong> <code>text/stex</code>.</p>
</body>
</html>

20
js/codemirror/mode/stex/stex.css vendored Normal file
View File

@ -0,0 +1,20 @@
span.css-at {color: #708;}
span.css-unit {color: #281;}
span.css-value {color: #708;}
span.css-identifier {color: black;}
span.css-selector {color: #11B;}
span.css-important {color: #00F;}
span.css-colorcode {color: #299;}
span.css-comment {color: #A70;}
span.css-string {color: #A22;}
span.stex-unit { color: #281; }
span.stex-identifier { color: black; }
span.stex-slash { color: #FAA; }
span.stex-command { color: #00F; }
span.stex-comment { color: #A70; }
span.stex-import { color: #00F; }
span.stex-filepath { color: #852626; }
span.stex-module { color: #852626; }
span.stex-error { text-decoration: underline; color: red; }
span.stex-string { color: #A22; }

167
js/codemirror/mode/stex/stex.js vendored Normal file
View File

@ -0,0 +1,167 @@
/*
* Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
* Licence: MIT
*/
CodeMirror.defineMode("stex", function(cmCfg, modeCfg)
{
function pushCommand(state, command) {
state.cmdState.push(command);
}
function peekCommand(state) {
if (state.cmdState.length>0)
return state.cmdState[state.cmdState.length-1];
else
return null;
}
function popCommand(state) {
if (state.cmdState.length>0) {
var plug = state.cmdState.pop();
plug.closeBracket();
}
}
function applyMostPowerful(state) {
var context = state.cmdState;
for (var i = context.length - 1; i >= 0; i--) {
var plug = context[i];
if (plug.name=="DEFAULT")
continue;
return plug.styleIdentifier();
}
return "stex-identifier";
}
function addPluginPattern(pluginName, cmdStyle, brackets, styles) {
return function () {
this.name=pluginName;
this.bracketNo = 0;
this.style=cmdStyle;
this.styles = styles;
this.brackets = brackets;
this.styleIdentifier = function(content) {
if (this.bracketNo<=this.styles.length)
return this.styles[this.bracketNo-1];
else
return null;
};
this.openBracket = function(content) {
this.bracketNo++;
return "stex-bracket";
};
this.closeBracket = function(content) {
};
}
}
var plugins = new Array();
plugins["importmodule"] = addPluginPattern("importmodule", "stex-command", "{[", ["stex-filepath", "stex-module"]);
plugins["documentclass"] = addPluginPattern("documentclass", "stex-command", "{[", ["", "stex-unit"]);
plugins["usepackage"] = addPluginPattern("documentclass", "stex-command", "[", ["stex-unit"]);
plugins["begin"] = addPluginPattern("documentclass", "stex-command", "[", ["stex-unit"]);
plugins["end"] = addPluginPattern("documentclass", "stex-command", "[", ["stex-unit"]);
plugins["DEFAULT"] = function () {
this.name="DEFAULT";
this.style="stex-command";
this.styleIdentifier = function(content) {
};
this.openBracket = function(content) {
};
this.closeBracket = function(content) {
};
};
function setState(state, f) {
state.f = f;
}
function normal(source, state) {
if (source.match(/^\\[a-z]+/)) {
var cmdName = source.current();
cmdName = cmdName.substr(1, cmdName.length-1);
var plug = plugins[cmdName];
if (typeof(plug) == 'undefined') {
plug = plugins["DEFAULT"];
}
plug = new plug();
pushCommand(state, plug);
setState(state, beginParams);
return plug.style;
}
var ch = source.next();
if (ch == "%") {
setState(state, inCComment);
return "stex-comment";
}
else if (ch=='}' || ch==']') {
plug = peekCommand(state);
if (plug) {
plug.closeBracket(ch);
setState(state, beginParams);
} else
return "stex-error";
return "stex-bracket";
} else if (ch=='{' || ch=='[') {
plug = plugins["DEFAULT"];
plug = new plug();
pushCommand(state, plug);
return "stex-bracket";
}
else if (/\d/.test(ch)) {
source.eatWhile(/[\w.%]/);
return "stex-unit";
}
else {
source.eatWhile(/[\w-_]/);
return applyMostPowerful(state);
}
}
function inCComment(source, state) {
source.skipToEnd();
setState(state, normal);
return "css-comment";
}
function beginParams(source, state) {
var ch = source.peek();
if (ch == '{' || ch == '[') {
var lastPlug = peekCommand(state);
var style = lastPlug.openBracket(ch);
source.eat(ch);
setState(state, normal);
return "stex-bracket";
}
if (/[ \t\r]/.test(ch)) {
source.eat(ch);
return null;
}
setState(state, normal);
lastPlug = peekCommand(state);
if (lastPlug) {
popCommand(state);
}
return normal(source, state);
}
return {
startState: function() { return { f:normal, cmdState:[] }; },
copyState: function(s) { return { f: s.f, cmdState: s.cmdState.slice(0, s.cmdState.length) }; },
token: function(stream, state) {
var t = state.f(stream, state);
var w = stream.current();
return t;
}
};
});
CodeMirror.defineMIME("text/x-stex", "stex");

42
js/codemirror/mode/xml/index.html vendored Normal file
View File

@ -0,0 +1,42 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: XML mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="xml.js"></script>
<link rel="stylesheet" href="xml.css">
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<link rel="stylesheet" href="../../css/docs.css">
</head>
<body>
<h1>CodeMirror 2: XML mode</h1>
<form><textarea id="code" name="code">
&lt;html style="color: green"&gt;
&lt;!-- this is a comment --&gt;
&lt;head&gt;
&lt;title&gt;HTML Example&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
The indentation tries to be &lt;em&gt;somewhat &amp;quot;do what
I mean&amp;quot;&lt;/em&gt;... but might not match your style.
&lt;/body&gt;
&lt;/html&gt;
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: {name: "xml", htmlMode: true}});
</script>
<p>The XML mode supports two configuration parameters:</p>
<dl>
<dt><code>htmlMode (boolean)</code></dt>
<dd>This switches the mode to parse HTML instead of XML. This
means attributes do not have to be quoted, and some elements
(such as <code>br</code>) do not require a closing tag.</dd>
<dt><code>alignCDATA (boolean)</code></dt>
<dd>Setting this to true will force the opening tag of CDATA
blocks to not be indented.</dd>
</dl>
<p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>
</body>
</html>

7
js/codemirror/mode/xml/xml.css vendored Normal file
View File

@ -0,0 +1,7 @@
span.xml-tag {color: #a0b;}
span.xml-attribute {color: #281;}
span.xml-attname {color: #00f;}
span.xml-comment {color: #a70;}
span.xml-cdata {color: #48a;}
span.xml-processing {color: #999;}
span.xml-entity {color: #a22;}

206
js/codemirror/mode/xml/xml.js vendored Normal file
View File

@ -0,0 +1,206 @@
CodeMirror.defineMode("xml", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var Kludges = parserConfig.htmlMode ? {
autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true,
"meta": true, "col": true, "frame": true, "base": true, "area": true},
doNotIndent: {"pre": true, "!cdata": true},
allowUnquoted: true
} : {autoSelfClosers: {}, doNotIndent: {"!cdata": true}, allowUnquoted: false};
var alignCDATA = parserConfig.alignCDATA;
// Return variables for tokenizers
var tagName, type;
function inText(stream, state) {
function chain(parser) {
state.tokenize = parser;
return parser(stream, state);
}
var ch = stream.next();
if (ch == "<") {
if (stream.eat("!")) {
if (stream.eat("[")) {
if (stream.match("CDATA[")) return chain(inBlock("xml-cdata", "]]>"));
else return null;
}
else if (stream.match("--")) return chain(inBlock("xml-comment", "-->"));
else if (stream.match("DOCTYPE")) {
stream.eatWhile(/[\w\._\-]/);
return chain(inBlock("xml-doctype", ">"));
}
else return null;
}
else if (stream.eat("?")) {
stream.eatWhile(/[\w\._\-]/);
state.tokenize = inBlock("xml-processing", "?>");
return "xml-processing";
}
else {
type = stream.eat("/") ? "closeTag" : "openTag";
stream.eatSpace();
tagName = "";
var c;
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
state.tokenize = inTag;
return "xml-tag";
}
}
else if (ch == "&") {
stream.eatWhile(/[^;]/);
stream.eat(";");
return "xml-entity";
}
else {
stream.eatWhile(/[^&<]/);
return null;
}
}
function inTag(stream, state) {
var ch = stream.next();
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "xml-tag";
}
else if (ch == "=") {
type = "equals";
return null;
}
else if (/[\'\"]/.test(ch)) {
state.tokenize = inAttribute(ch);
return state.tokenize(stream, state);
}
else {
stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
return "xml-word";
}
}
function inAttribute(quote) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inTag;
break;
}
}
return "xml-attribute";
};
}
function inBlock(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator)) {
state.tokenize = inText;
break;
}
stream.next();
}
return style;
};
}
var curState, setStyle;
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function pushContext(tagName, startOfLine) {
var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
curState.context = {
prev: curState.context,
tagName: tagName,
indent: curState.indented,
startOfLine: startOfLine,
noIndent: noIndent
};
}
function popContext() {
if (curState.context) curState.context = curState.context.prev;
}
function element(type) {
if (type == "openTag") {curState.tagName = tagName; return cont(attributes, endtag(curState.startOfLine));}
else if (type == "closeTag") {popContext(); return cont(endclosetag);}
else if (type == "xml-cdata") {
if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
if (curState.tokenize == inText) popContext();
return cont();
}
else return cont();
}
function endtag(startOfLine) {
return function(type) {
if (type == "selfcloseTag" ||
(type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())))
return cont();
if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();}
return cont();
};
}
function endclosetag(type) {
if (type == "endTag") return cont();
return pass();
}
function attributes(type) {
if (type == "xml-word") {setStyle = "xml-attname"; return cont(attributes);}
if (type == "equals") return cont(attvalue, attributes);
return pass();
}
function attvalue(type) {
if (type == "xml-word" && Kludges.allowUnquoted) {setStyle = "xml-attribute"; return cont();}
if (type == "xml-attribute") return cont();
return pass();
}
return {
startState: function() {
return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
},
token: function(stream, state) {
if (stream.sol()) {
state.startOfLine = true;
state.indented = stream.indentation();
}
if (stream.eatSpace()) return null;
setStyle = type = tagName = null;
var style = state.tokenize(stream, state);
if ((style || type) && style != "xml-comment") {
curState = state;
while (true) {
var comb = state.cc.pop() || element;
if (comb(type || style)) break;
}
}
state.startOfLine = false;
return setStyle || style;
},
indent: function(state, textAfter) {
var context = state.context;
if (context && context.noIndent) return 0;
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
if (context && /^<\//.test(textAfter))
context = context.prev;
while (context && !context.startOfLine)
context = context.prev;
if (context) return context.indent + indentUnit;
else return 0;
},
electricChars: "/"
};
});
CodeMirror.defineMIME("application/xml", "xml");
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});

View File

@ -0,0 +1,140 @@
<!doctype html>
<html>
<head>
<title>CodeMirror</title>
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel="alternate" href="http://twitter.com/statuses/user_timeline/242283288.rss" type="application/rss+xml"/>
</head>
<body>
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
<pre class="grey">
<img src="css/baboon.png" class="logo" alt="logo"/>/* Old release history */
</pre>
<p class="rel">17-12-2010: <a href="http://codemirror.net/codemirror-0.92.zip">Version 0.92</a>:</p>
<ul class="rel-note">
<li>Make CodeMirror work in XHTML documents.</li>
<li>Fix bug in handling of backslashes in Python strings.</li>
<li>The <code>styleNumbers</code> option is now officially
supported and documented.</li>
<li><code>onLineNumberClick</code> option added.</li>
<li>More consistent names <code>onLoad</code> and
<code>onCursorActivity</code> callbacks. Old names still work, but
are deprecated.</li>
<li>Add a <a href="contrib/freemarker/index.html">Freemarker</a> mode.</li>
</ul>
<p class="rel">11-11-2010: <a
href="http://codemirror.net/codemirror-0.91.zip">Version 0.91</a>:</p>
<ul class="rel-note">
<li>Adds support for <a href="contrib/java">Java</a>.</li>
<li>Small additions to the <a href="contrib/php">PHP</a> and <a href="contrib/sql">SQL</a> parsers.</li>
<li>Work around various <a href="https://bugs.webkit.org/show_bug.cgi?id=47806">Webkit</a> <a href="https://bugs.webkit.org/show_bug.cgi?id=23474">issues</a>.</li>
<li>Fix <code>toTextArea</code> to update the code in the textarea.</li>
<li>Add a <code>noScriptCaching</code> option (hack to ease development).</li>
<li>Make sub-modes of <a href="mixedtest.html">HTML mixed</a> mode configurable.</li>
</ul>
<p class="rel">02-10-2010: <a
href="http://codemirror.net/codemirror-0.9.zip">Version 0.9</a>:</p>
<ul class="rel-note">
<li>Add support for searching backwards.</li>
<li>There are now parsers for <a href="contrib/scheme/index.html">Scheme</a>, <a href="contrib/xquery/index.html">XQuery</a>, and <a href="contrib/ometa/index.html">OmetaJS</a>.</li>
<li>Makes <code>height: "dynamic"</code> more robust.</li>
<li>Fixes bug where paste did not work on OS X.</li>
<li>Add a <code>enterMode</code> and <code>electricChars</code> options to make indentation even more customizable.</li>
<li>Add <code>firstLineNumber</code> option.</li>
<li>Fix bad handling of <code>@media</code> rules by the CSS parser.</li>
<li>Take a new, more robust approach to working around the invisible-last-line bug in WebKit.</li>
</ul>
<p class="rel">22-07-2010: <a
href="http://codemirror.net/codemirror-0.8.zip">Version 0.8</a>:</p>
<ul class="rel-note">
<li>Add a <code>cursorCoords</code> method to find the screen
coordinates of the cursor.</li>
<li>A number of fixes and support for more syntax in the PHP parser.</li>
<li>Fix indentation problem with JSON-mode JS parser in Webkit.</li>
<li>Add a <a href="compress.html">minification</a> UI.</li>
<li>Support a <code>height: dynamic</code> mode, where the editor's
height will adjust to the size of its content.</li>
<li>Better support for IME input mode.</li>
<li>Fix JavaScript parser getting confused when seeing a no-argument
function call.</li>
<li>Have CSS parser see the difference between selectors and other
identifiers.</li>
<li>Fix scrolling bug when pasting in a horizontally-scrolled
editor.</li>
<li>Support <code>toTextArea</code> method in instances created with
<code>fromTextArea</code>.</li>
<li>Work around new Opera cursor bug that causes the cursor to jump
when pressing backspace at the end of a line.</li>
</ul>
<p class="rel">27-04-2010: <a
href="http://codemirror.net/codemirror-0.67.zip">Version
0.67</a>:</p>
<p class="rel-note">More consistent page-up/page-down behaviour
across browsers. Fix some issues with hidden editors looping forever
when line-numbers were enabled. Make PHP parser parse
<code>"\\"</code> correctly. Have <code>jumpToLine</code> work on
line handles, and add <code>cursorLine</code> function to fetch the
line handle where the cursor currently is. Add new
<code>setStylesheet</code> function to switch style-sheets in a
running editor.</p>
<p class="rel">01-03-2010: <a
href="http://codemirror.net/codemirror-0.66.zip">Version
0.66</a>:</p>
<p class="rel-note">Adds <code>removeLine</code> method to API.
Introduces the <a href="contrib/plsql/index.html">PLSQL parser</a>.
Marks XML errors by adding (rather than replacing) a CSS class, so
that they can be disabled by modifying their style. Fixes several
selection bugs, and a number of small glitches.</p>
<p class="rel">12-11-2009: <a
href="http://codemirror.net/codemirror-0.65.zip">Version
0.65</a>:</p>
<p class="rel-note">Add support for having both line-wrapping and
line-numbers turned on, make paren-highlighting style customisable
(<code>markParen</code> and <code>unmarkParen</code> config
options), work around a selection bug that Opera
<em>re</em>introduced in version 10.</p>
<p class="rel">23-10-2009: <a
href="http://codemirror.net/codemirror-0.64.zip">Version
0.64</a>:</p>
<p class="rel-note">Solves some issues introduced by the
paste-handling changes from the previous release. Adds
<code>setSpellcheck</code>, <code>setTextWrapping</code>,
<code>setIndentUnit</code>, <code>setUndoDepth</code>,
<code>setTabMode</code>, and <code>setLineNumbers</code> to
customise a running editor. Introduces an <a
href="contrib/sql/index.html">SQL</a> parser. Fixes a few small
problems in the <a href="contrib/python/index.html">Python</a>
parser. And, as usual, add workarounds for various newly discovered
browser incompatibilities.</p>
<p class="rel"><em>31-08-2009</em>: <a
href="http://codemirror.net/codemirror-0.63.zip">Version
0.63</a>:</p>
<p class="rel-note"> Overhaul of paste-handling (less fragile), fixes for several
serious IE8 issues (cursor jumping, end-of-document bugs) and a number
of small problems.</p>
<p class="rel"><em>30-05-2009</em>: <a
href="http://codemirror.net/codemirror-0.62.zip">Version
0.62</a>:</p>
<p class="rel-note">Introduces <a href="contrib/python/index.html">Python</a>
and <a href="contrib/lua/index.html">Lua</a> parsers. Add
<code>setParser</code> (on-the-fly mode changing) and
<code>clearHistory</code> methods. Make parsing passes time-based
instead of lines-based (see the <code>passTime</code> option).</p>
<script type="text/javascript" src="css/font.js"></script>
</body></html>

View File

@ -0,0 +1,29 @@
<!doctype html>
<html>
<head>
<title>CodeMirror 2: Test Suite</title>
<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<link rel="stylesheet" href="../mode/javascript/javascript.css">
<script src="../mode/javascript/javascript.js"></script>
<style type="text/css">
.ok {color: #0e0;}
.failure {color: #e00;}
.error {color: #c90;}
</style>
</head>
<body>
<h1>CodeMirror 2: Test Suite</h1>
<p>A limited set of programmatic sanity tests for CodeMirror.</p>
<pre id=output></pre>
<div style="visibility: hidden" id=testground>
<form><textarea id="code" name="code"></textarea><input type=submit value=ok name=submit></form>
</div>
<script src="test.js"></script>
</body>
</html>

248
js/codemirror/test/test.js Normal file
View File

@ -0,0 +1,248 @@
var tests = [];
test("fromTextArea", function() {
var te = document.getElementById("code");
te.value = "CONTENT";
var cm = CodeMirror.fromTextArea(te);
is(!te.offsetHeight);
eq(cm.getValue(), "CONTENT");
cm.setValue("foo\nbar");
eq(cm.getValue(), "foo\nbar");
cm.save();
is(/^foo\r?\nbar$/.test(te.value));
cm.setValue("xxx");
cm.toTextArea();
is(te.offsetHeight);
eq(te.value, "xxx");
});
testCM("getRange", function(cm) {
eq(cm.getLine(0), "1234");
eq(cm.getLine(1), "5678");
eq(cm.getLine(2), null);
eq(cm.getLine(-1), null);
eq(cm.getRange({line: 0, ch: 0}, {line: 0, ch: 3}), "123");
eq(cm.getRange({line: 0, ch: -1}, {line: 0, ch: 200}), "1234");
eq(cm.getRange({line: 0, ch: 2}, {line: 1, ch: 2}), "34\n56");
eq(cm.getRange({line: 1, ch: 2}, {line: 100, ch: 0}), "78");
}, {value: "1234\n5678"});
testCM("replaceRange", function(cm) {
eq(cm.getValue(), "");
cm.replaceRange("foo\n", {line: 0, ch: 0});
eq(cm.getValue(), "foo\n");
cm.replaceRange("a\nb", {line: 0, ch: 1});
eq(cm.getValue(), "fa\nboo\n");
eq(cm.lineCount(), 3);
cm.replaceRange("xyzzy", {line: 0, ch: 0}, {line: 1, ch: 1});
eq(cm.getValue(), "xyzzyoo\n");
cm.replaceRange("abc", {line: 0, ch: 0}, {line: 10, ch: 0});
eq(cm.getValue(), "abc");
eq(cm.lineCount(), 1);
});
testCM("selection", function(cm) {
cm.setSelection({line: 0, ch: 4}, {line: 2, ch: 2});
is(cm.somethingSelected());
eq(cm.getSelection(), "11\n222222\n33");
eqPos(cm.getCursor(false), {line: 2, ch: 2});
eqPos(cm.getCursor(true), {line: 0, ch: 4});
cm.setSelection({line: 1, ch: 0});
is(!cm.somethingSelected());
eq(cm.getSelection(), "");
eqPos(cm.getCursor(true), {line: 1, ch: 0});
cm.replaceSelection("abc");
eq(cm.getSelection(), "abc");
eq(cm.getValue(), "111111\nabc222222\n333333");
cm.replaceSelection("def", "end");
eq(cm.getSelection(), "");
eqPos(cm.getCursor(true), {line: 1, ch: 3});
cm.setCursor({line: 2, ch: 1});
eqPos(cm.getCursor(true), {line: 2, ch: 1});
cm.setCursor(1, 2);
eqPos(cm.getCursor(true), {line: 1, ch: 2});
}, {value: "111111\n222222\n333333"});
testCM("lines", function(cm) {
eq(cm.getLine(0), "111111");
eq(cm.getLine(1), "222222");
eq(cm.getLine(-1), null);
cm.removeLine(1);
cm.setLine(1, "abc");
eq(cm.getValue(), "111111\nabc");
}, {value: "111111\n222222\n333333"});
testCM("indent", function(cm) {
cm.indentLine(1);
eq(cm.getLine(1), " blah();");
cm.setOption("indentUnit", 8);
cm.indentLine(1);
eq(cm.getLine(1), "\tblah();");
}, {value: "if (x) {\nblah();\n}", indentUnit: 3, indentWithTabs: true});
test("defaults", function() {
var olddefaults = CodeMirror.defaults, defs = CodeMirror.defaults = {};
for (var opt in olddefaults) defs[opt] = olddefaults[opt];
defs.indentUnit = 5;
defs.value = "uu";
defs.enterMode = "keep";
defs.tabindex = 55;
var place = document.getElementById("testground"), cm = CodeMirror(place);
try {
eq(cm.getOption("indentUnit"), 5);
cm.setOption("indentUnit", 10);
eq(defs.indentUnit, 5);
eq(cm.getValue(), "uu");
eq(cm.getOption("enterMode"), "keep");
eq(cm.getInputField().tabindex, 55);
}
finally {
CodeMirror.defaults = olddefaults;
place.removeChild(cm.getWrapperElement());
}
});
testCM("lineInfo", function(cm) {
eq(cm.lineInfo(-1), null);
var lh = cm.setMarker(1, "FOO", "bar");
var info = cm.lineInfo(1);
eq(info.text, "222222");
eq(info.markerText, "FOO");
eq(info.markerClass, "bar");
eq(info.line, 1);
eq(cm.lineInfo(2).markerText, null);
cm.clearMarker(lh);
eq(cm.lineInfo(1).markerText, null);
}, {value: "111111\n222222\n333333"});
testCM("coords", function(cm) {
cm.getWrapperElement().style.height = "100px";
var content = [];
for (var i = 0; i < 200; ++i) content.push("------------------------------" + i);
cm.setValue(content.join("\n"));
var top = cm.charCoords({line: 0, ch: 0});
var bot = cm.charCoords({line: 200, ch: 30});
is(top.x < bot.x);
is(top.y < bot.y);
is(top.y < top.yBot);
cm.getWrapperElement().scrollTop = 100;
cm.refresh();
var top2 = cm.charCoords({line: 0, ch: 0});
is(top.y > top2.y);
eq(top.x, top2.x);
});
testCM("coordsChar", function(cm) {
var content = [];
for (var i = 0; i < 70; ++i) content.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
cm.setValue(content.join("\n"));
for (var x = 0; x < 35; x += 2) {
for (var y = 0; y < 70; y += 5) {
cm.setCursor(y, x);
var pos = cm.coordsChar(cm.charCoords({line: y, ch: x}));
eq(pos.line, y);
eq(pos.ch, x);
}
}
});
testCM("undo", function(cm) {
cm.setLine(0, "def");
eq(cm.historySize().undo, 1);
cm.undo();
eq(cm.getValue(), "abc");
eq(cm.historySize().undo, 0);
eq(cm.historySize().redo, 1);
cm.redo();
eq(cm.getValue(), "def");
eq(cm.historySize().undo, 1);
eq(cm.historySize().redo, 0);
cm.setValue("1\n\n\n2");
eq(cm.historySize().undo, 0);
for (var i = 0; i < 20; ++i) {
cm.replaceRange("a", {line: 0, ch: 0});
cm.replaceRange("b", {line: 3, ch: 0});
}
eq(cm.historySize().undo, 40);
for (var i = 0; i < 38; ++i) cm.undo();
eq(cm.historySize().undo, 2);
eq(cm.historySize().redo, 38);
eq(cm.getValue(), "a1\n\n\nb2");
cm.setOption("undoDepth", 10);
for (var i = 0; i < 20; ++i) {
cm.replaceRange("a", {line: 0, ch: 0});
cm.replaceRange("b", {line: 3, ch: 0});
}
eq(cm.historySize().undo, 10);
}, {value: "abc"});
testCM("undoMultiLine", function(cm) {
cm.replaceRange("x", {line:0, ch: 0});
cm.replaceRange("y", {line:1, ch: 0});
cm.undo();
eq(cm.getValue(), "abc\ndef\nghi");
cm.replaceRange("y", {line:1, ch: 0});
cm.replaceRange("x", {line:0, ch: 0});
cm.undo();
eq(cm.getValue(), "abc\ndef\nghi");
cm.replaceRange("y", {line:2, ch: 0});
cm.replaceRange("x", {line:1, ch: 0});
cm.replaceRange("z", {line:2, ch: 0});
cm.undo();
eq(cm.getValue(), "abc\ndef\nghi");
}, {value: "abc\ndef\nghi"});
// Scaffolding
function htmlEscape(str) {
return str.replace(/[<&]/g, function(str) {return str == "&" ? "&amp;" : "&lt;";});
}
function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
}
function Failure(why) {this.message = why;}
function test(name, run) {tests.push({name: name, func: run});}
function testCM(name, run, opts) {
test(name, function() {
var place = document.getElementById("testground"), cm = CodeMirror(place, opts);
try {run(cm);}
finally {place.removeChild(cm.getWrapperElement());}
});
}
function runTests() {
var failures = [], run = 0;
for (var i = 0; i < tests.length; ++i) {
var test = tests[i];
try {test.func();}
catch(e) {
if (e instanceof Failure)
failures.push({type: "failure", test: test.name, text: e.message});
else
failures.push({type: "error", test: test.name, text: e.toString()});
}
run++;
}
var html = [run + " tests run."];
if (failures.length)
forEach(failures, function(fail) {
html.push(fail.test + ': <span class="' + fail.type + '">' + htmlEscape(fail.text) + "</span>");
});
else html.push('<span class="ok">All passed.</span>');
document.getElementById("output").innerHTML = html.join("\n");
}
function eq(a, b, msg) {
if (a != b) throw new Failure(a + " != " + b + (msg ? " (" + msg + ")" : ""));
}
function eqPos(a, b, msg) {
eq(a.line, b.line, msg);
eq(a.ch, b.ch, msg);
}
function is(a, msg) {
if (!a) throw new Failure("assertion failed" + (msg ? " (" + msg + ")" : ""));
}
window.onload = runTests;