14 changes: 14 additions & 0 deletions addon/lint/yaml-lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Depends on js-yaml.js from https://github.com/nodeca/js-yaml

// declare global: jsyaml

CodeMirror.registerHelper("lint", "yaml", function(text) {
var found = [];
try { jsyaml.load(text); }
catch(e) {
var loc = e.mark;
found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message });
}
return found;
});
CodeMirror.yamlValidator = CodeMirror.lint.yaml; // deprecated
2 changes: 1 addition & 1 deletion addon/merge/dep/diff_match_patch.js
4 changes: 2 additions & 2 deletions addon/runmode/runmode.node.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ exports.resolveMode = function(spec) {
else return spec || {name: "null"};
};
exports.getMode = function(options, spec) {
spec = exports.resolveMode(mimeModes[spec]);
spec = exports.resolveMode(spec);
var mfactory = modes[spec.name];
if (!mfactory) throw new Error("Unknown mode: " + spec);
return mfactory(options, spec);
};
exports.registerHelper = exports.registerGlobalHelper = Math.min;

exports.runMode = function(string, modespec, callback) {
exports.runMode = function(string, modespec, callback, options) {
var mode = exports.getMode({indentUnit: 2}, modespec);
var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) {
Expand Down
2 changes: 2 additions & 0 deletions addon/scroll/scrollpastend.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.off("change", onChange);
cm.off("refresh", updateBottomMargin);
cm.display.lineSpace.parentNode.style.paddingBottom = "";
cm.state.scrollPastEndPadding = null;
}
if (val) {
cm.on("change", onChange);
cm.on("refresh", updateBottomMargin);
updateBottomMargin(cm);
}
});
Expand Down
12 changes: 9 additions & 3 deletions addon/search/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@
}
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i") : query;
if (isRE) {
query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i");
if (query.test("")) query = /x^/;
} else if (query == "") {
query = /x^/;
}
return query;
}
var queryDialog =
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
Expand Down Expand Up @@ -107,7 +113,7 @@
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") {
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
cursor.replace(text.replace(/\$(\d)/, function(_, i) {return match[i];}));
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
} else cursor.replace(text);
}
});
Expand All @@ -128,7 +134,7 @@
};
var doReplace = function(match) {
cursor.replace(typeof query == "string" ? text :
text.replace(/\$(\d)/, function(_, i) {return match[i];}));
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
advance();
};
advance();
Expand Down
2 changes: 1 addition & 1 deletion bin/release
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ rewrite("doc/compress.html", function(cmp) {
});

rewrite("index.html", function(index) {
return index.replace(/<strong>version 3.20<\/strong>/,
return index.replace(/<strong>version \d+\.\d+<\/strong>/,
"<strong>version " + simple + "</strong>");
});
2 changes: 1 addition & 1 deletion bin/source-highlight
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function ensureMode(name) {
ensureMode(modeName);

function esc(str) {
return str.replace(/[<&]/, function(ch) { return ch == "&" ? "&amp;" : "&lt;"; });
return str.replace(/[<&]/g, function(ch) { return ch == "&" ? "&amp;" : "&lt;"; });
}

var code = fs.readFileSync("/dev/stdin", "utf8");
Expand Down
3 changes: 1 addition & 2 deletions demo/changemode.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ <h2>Mode-Changing Demo</h2>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: "scheme",
lineNumbers: true,
tabMode: "indent"
lineNumbers: true
});
var pending;
editor.on("change", function() {
Expand Down
17 changes: 16 additions & 1 deletion demo/folding.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
<script src="../addon/fold/foldgutter.js"></script>
<script src="../addon/fold/brace-fold.js"></script>
<script src="../addon/fold/xml-fold.js"></script>
<script src="../addon/fold/markdown-fold.js"></script>
<script src="../addon/fold/comment-fold.js"></script>
<script src="../mode/javascript/javascript.js"></script>
<script src="../mode/xml/xml.js"></script>
<script src="../mode/markdown/markdown.js"></script>
<style type="text/css">
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
</style>
Expand All @@ -39,8 +41,10 @@ <h2>Code Folding Demo</h2>
<form>
<div style="max-width: 50em; margin-bottom: 1em">JavaScript:<br>
<textarea id="code" name="code"></textarea></div>
<div style="max-width: 50em">HTML:<br>
<div style="max-width: 50em; margin-bottom: 1em">HTML:<br>
<textarea id="code-html" name="code-html"></textarea></div>
<div style="max-width: 50em">Markdown:<br>
<textarea id="code-markdown" name="code"></textarea></div>
</form>
<script id="script">
/*
Expand All @@ -53,6 +57,8 @@ <h2>Code Folding Demo</h2>
sc.innerHTML = "";
var te_html = document.getElementById("code-html");
te_html.value = document.documentElement.innerHTML;
var te_markdown = document.getElementById("code-markdown");
te_markdown.value = "# Foo\n## Bar\n\nblah blah\n\n## Baz\n\nblah blah\n\n# Quux\n\nblah blah\n"

window.editor = CodeMirror.fromTextArea(te, {
mode: "javascript",
Expand All @@ -74,6 +80,15 @@ <h2>Code Folding Demo</h2>
});
editor_html.foldCode(CodeMirror.Pos(0, 0));
editor_html.foldCode(CodeMirror.Pos(21, 0));

window.editor_markdown = CodeMirror.fromTextArea(te_markdown, {
mode: "markdown",
lineNumbers: true,
lineWrapping: true,
extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }},
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
});
};
</script>
</article>
Expand Down
105 changes: 29 additions & 76 deletions demo/fullscreen.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,85 +27,38 @@
<article>
<h2>Full Screen Editing</h2>
<form><textarea id="code" name="code" rows="5">
<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>
<dl>
<dt id="option_indentWithTabs"><code><strong>indentWithTabs</strong>: boolean</code></dt>
<dd>Whether, when indenting, the first N*<code>tabSize</code>
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_electricChars"><code><strong>electricChars</strong>: 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_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_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_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_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_specialChars"><code><strong>specialChars</strong>: RegExp</code></dt>
<dd>A regular expression used to determine which characters
should be replaced by a
special <a href="#option_specialCharPlaceholder">placeholder</a>.
Mostly useful for non-printing special characters. The default
is <code>/[\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/</code>.</dd>
<dt id="option_specialCharPlaceholder"><code><strong>specialCharPlaceholder</strong>: function(char) → Element</code></dt>
<dd>A function that, given a special character identified by
the <a href="#option_specialChars"><code>specialChars</code></a>
option, produces a DOM node that is used to represent the
character. By default, a red dot (<span style="color: red">•</span>)
is shown, with a title tooltip to indicate the character code.</dd>

<dt id="option_rtlMoveVisually"><code><strong>rtlMoveVisually</strong>: boolean</code></dt>
<dd>Determines whether horizontal cursor movement through
right-to-left (Arabic, Hebrew) text is visual (pressing the left
arrow moves the cursor left) or logical (pressing the left arrow
moves to the next lower index in the string, which is visually
right in right-to-left text). The default is <code>false</code>
on Windows, and <code>true</code> on other platforms.</dd>
</dl>
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
Expand Down
3 changes: 1 addition & 2 deletions demo/preview.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ <h2>HTML5 preview</h2>
var delay;
// Initialize CodeMirror editor with a nice html5 canvas demo.
var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
mode: 'text/html',
tabMode: 'indent'
mode: 'text/html'
});
editor.on("change", function() {
clearTimeout(delay);
Expand Down
54 changes: 54 additions & 0 deletions demo/rulers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<!doctype html>

<title>CodeMirror: Ruler Demo</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../doc/docs.css">

<link rel="stylesheet" href="../lib/codemirror.css">
<script src="../lib/codemirror.js"></script>
<script src="../addon/display/rulers.js"></script>
<style type="text/css">
.CodeMirror {border-top: 1px solid #888; border-bottom: 1px solid #888;}
.ruler1 { border-left: 1px solid #fcc; }
.ruler2 { border-left: 1px solid #f5f577; }
.ruler3 { border-left: 1px solid #cfc; }
.ruler4 { border-left: 1px solid #aff; }
.ruler5 { border-left: 1px solid #ccf; }
.ruler6 { border-left: 1px solid #fcf; }
</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../doc/logo.png"></a>

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

<article>
<h2>Ruler Demo</h2>

<script type="text/javascript">
var nums = "0123456789", space = " ";
var rulers = [], value = "";
for (var i = 1; i <= 6; i++) {
rulers.push({className: "ruler" + i, column: i * 10});
for (var j = 1; j < i; j++) value += space;
value += nums + "\n";
}
var editor = CodeMirror(document.body.lastChild, {
rulers: rulers,
value: value + value + value,
lineNumbers: true
});
</script>

<p>Demonstration of
the <a href="../doc/manual.html#addon_rulers">rulers</a> addon, which
displays vertical lines at given column offsets.</p>

</article>
67 changes: 30 additions & 37 deletions demo/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,45 +31,38 @@
<article>
<h2>Search/Replace Demo</h2>
<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>
<dl>
<dt id="option_indentWithTabs"><code><strong>indentWithTabs</strong>: boolean</code></dt>
<dd>Whether, when indenting, the first N*<code>tabSize</code>
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_electricChars"><code><strong>electricChars</strong>: 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_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_specialChars"><code><strong>specialChars</strong>: RegExp</code></dt>
<dd>A regular expression used to determine which characters
should be replaced by a
special <a href="#option_specialCharPlaceholder">placeholder</a>.
Mostly useful for non-printing special characters. The default
is <code>/[\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/</code>.</dd>
<dt id="option_specialCharPlaceholder"><code><strong>specialCharPlaceholder</strong>: function(char) → Element</code></dt>
<dd>A function that, given a special character identified by
the <a href="#option_specialChars"><code>specialChars</code></a>
option, produces a DOM node that is used to represent the
character. By default, a red dot (<span style="color: red">•</span>)
is shown, with a title tooltip to indicate the character code.</dd>

<dt id="option_rtlMoveVisually"><code><strong>rtlMoveVisually</strong>: boolean</code></dt>
<dd>Determines whether horizontal cursor movement through
right-to-left (Arabic, Hebrew) text is visual (pressing the left
arrow moves the cursor left) or logical (pressing the left arrow
moves to the next lower index in the string, which is visually
right in right-to-left text). The default is <code>false</code>
on Windows, and <code>true</code> on other platforms.</dd>
</dl>
</textarea></form>

<script>
Expand Down
2 changes: 2 additions & 0 deletions demo/theme.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<link rel="stylesheet" href="../theme/erlang-dark.css">
<link rel="stylesheet" href="../theme/lesser-dark.css">
<link rel="stylesheet" href="../theme/mbo.css">
<link rel="stylesheet" href="../theme/mdn-like.css">
<link rel="stylesheet" href="../theme/midnight.css">
<link rel="stylesheet" href="../theme/monokai.css">
<link rel="stylesheet" href="../theme/neat.css">
Expand Down Expand Up @@ -83,6 +84,7 @@ <h2>Theme Demo</h2>
<option>erlang-dark</option>
<option>lesser-dark</option>
<option>mbo</option>
<option>mdn-like</option>
<option>midnight</option>
<option>monokai</option>
<option>neat</option>
Expand Down
12 changes: 6 additions & 6 deletions demo/variableheight.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
<style type="text/css">
.CodeMirror {border: 1px solid silver; border-width: 1px 2px; }
.cm-header { font-family: arial; }
.cm-header1 { font-size: 150%; }
.cm-header2 { font-size: 130%; }
.cm-header3 { font-size: 120%; }
.cm-header4 { font-size: 110%; }
.cm-header5 { font-size: 100%; }
.cm-header6 { font-size: 90%; }
.cm-header-1 { font-size: 150%; }
.cm-header-2 { font-size: 130%; }
.cm-header-3 { font-size: 120%; }
.cm-header-4 { font-size: 110%; }
.cm-header-5 { font-size: 100%; }
.cm-header-6 { font-size: 90%; }
.cm-strong { font-size: 140%; }
</style>
<div id=nav>
Expand Down
5 changes: 5 additions & 0 deletions doc/compress.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ <h2>Script compression helper</h2>
<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/codemirror?a=blob_plain;hb=3.22.0;f=">3.22</option>
<option value="http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=3.21.0;f=">3.21</option>
<option value="http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=3.20.0;f=">3.20</option>
<option value="http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=3.19.0;f=">3.19</option>
Expand Down Expand Up @@ -126,6 +127,7 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/mode/pig/pig.js">pig.js</option>
<option value="http://codemirror.net/mode/properties/properties.js">properties.js</option>
<option value="http://codemirror.net/mode/python/python.js">python.js</option>
<option value="http://codemirror.net/mode/puppet/puppet.js">puppet.js</option>
<option value="http://codemirror.net/mode/q/q.js">q.js</option>
<option value="http://codemirror.net/mode/r/r.js">r.js</option>
<option value="http://codemirror.net/mode/rpm/changes/changes.js">rpm/changes.js</option>
Expand Down Expand Up @@ -182,6 +184,7 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/addon/lint/json-lint.js">json-lint.js</option>
<option value="http://codemirror.net/addon/lint/lint.js">lint.js</option>
<option value="http://codemirror.net/addon/mode/loadmode.js">loadmode.js</option>
<option value="http://codemirror.net/addon/fold/markdown-fold.js">markdown-fold.js</option>
<option value="http://codemirror.net/addon/selection/mark-selection.js">mark-selection.js</option>
<option value="http://codemirror.net/addon/search/match-highlighter.js">match-highlighter.js</option>
<option value="http://codemirror.net/addon/edit/matchbrackets.js">matchbrackets.js</option>
Expand All @@ -192,6 +195,7 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/addon/hint/pig-hint.js">pig-hint.js</option>
<option value="http://codemirror.net/addon/display/placeholder.js">placeholder.js</option>
<option value="http://codemirror.net/addon/hint/python-hint.js">python-hint.js</option>
<option value="http://codemirror.net/addon/display/rulers.js">rulers.js</option>
<option value="http://codemirror.net/addon/runmode/runmode.js">runmode.js</option>
<option value="http://codemirror.net/addon/runmode/runmode.node.js">runmode.node.js</option>
<option value="http://codemirror.net/addon/runmode/runmode-standalone.js">runmode-standalone.js</option>
Expand All @@ -203,6 +207,7 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/addon/tern/tern.js">tern.js</option>
<option value="http://codemirror.net/addon/fold/xml-fold.js">xml-fold.js</option>
<option value="http://codemirror.net/addon/hint/xml-hint.js">xml-hint.js</option>
<option value="http://codemirror.net/addon/hint/yaml-lint.js">yaml-lint.js</option>
</optgroup>
<optgroup label="Keymaps">
<option value="http://codemirror.net/keymap/emacs.js">emacs.js</option>
Expand Down
4 changes: 3 additions & 1 deletion doc/docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ article {

#nav {
position: fixed;
top: 30px;
padding-top: 30px;
max-height: 100%;
overflow-y:scroll;
left: 0; right: none;
width: 160px;
padding-right: 350px;
Expand Down
51 changes: 38 additions & 13 deletions doc/manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@

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

<ul>
<li><a href="../index.html">Home</a>
<li><a href="#overview" class=active data-default="true">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
<li><a href="../index.html">Home</a></li>
<li><a href="#overview" class=active data-default="true">Manual</a></li>
<li><a href="https://github.com/marijnh/codemirror">Code</a></li>
</ul>
<ul>
<li><a href="#usage">Basic Usage</a></li>
Expand Down Expand Up @@ -446,7 +445,7 @@ <h2>Events</h2>

<p>Various CodeMirror-related objects emit events, which allow
client code to react to various situations. Handlers for such
events can be registed with the <a href="#on"><code>on</code></a>
events can be registered with the <a href="#on"><code>on</code></a>
and <a href="#off"><code>off</code></a> methods on the objects
that the event fires on. To fire your own events,
use <code>CodeMirror.signal(target, name, args...)</code>,
Expand Down Expand Up @@ -1262,7 +1261,7 @@ <h3 id="api_marker">Text-marking methods</h3>
only in its target document.</dd>
</dl>
The method will return an object that represents the marker
(with constuctor <code>CodeMirror.TextMarker</code>), which
(with constructor <code>CodeMirror.TextMarker</code>), which
exposes three methods:
<code><strong>clear</strong>()</code>, to remove the mark,
<code><strong>find</strong>()</code>, which returns
Expand Down Expand Up @@ -1294,6 +1293,9 @@ <h3 id="api_marker">Text-marking methods</h3>
to the left instead.</dd>
</dl></dd>

<dt id="findMarks"><code><strong>doc.findMarks</strong>(from: {line, ch}, to: {line, ch}) → array&lt;TextMarker&gt;</code></dt>
<dd>Returns an array of all the bookmarks and marked ranges
found between the given positions.</dd>
<dt id="findMarksAt"><code><strong>doc.findMarksAt</strong>(pos: {line, ch}) → array&lt;TextMarker&gt;</code></dt>
<dd>Returns an array of all the bookmarks and marked ranges
present at the given position.</dd>
Expand Down Expand Up @@ -2065,7 +2067,7 @@ <h2>Addons</h2>
uses <code>CodeMirror.hint.fromList</code> to complete from
those.</dd>
<dd>When completions
aren't simple strings, they should be objects with the folowing
aren't simple strings, they should be objects with the following
properties:
<dl>
<dt><code><strong>text</strong>: string</code></dt>
Expand All @@ -2082,6 +2084,12 @@ <h2>Addons</h2>
<dt><code><strong>hint</strong>: fn(CodeMirror, self, data)</code></dt>
<dd>A method used to actually apply the completion, instead of
the default behavior.</dd>
<dt><code><strong>from</strong>: {line, ch}</code></dt>
<dd>Optional <code>from</code> position that will be used by <code>pick()</code> instead
of the global one passed with the full list of completions.</dd>
<dt><code><strong>to</strong>: {line, ch}</code></dt>
<dd>Optional <code>to</code> position that will be used by <code>pick()</code> instead
of the global one passed with the full list of completions.</dd>
</dl>
The plugin understands the following options (the options object
will also be passed along to the hinting function, which may
Expand Down Expand Up @@ -2110,7 +2118,11 @@ <h2>Addons</h2>
has <code>moveFocus(n)</code>, <code>setFocus(n)</code>, <code>pick()</code>,
and <code>close()</code> methods (see the source for details),
that can be used to change the focused element, pick the
current element or close the menu.</dd>
current element or close the menu. Additionnaly <code>menuSize()</code>
can give you access to the size of the current dropdown menu,
<code>length</code> give you the number of availlable completions, and
<code>data</code> give you full access to the completion returned by the
hinting function.</dd>
<dt><code><strong>extraKeys</strong>: keymap</code></dt>
<dd>Like <code>customKeys</code> above, but the bindings will
be added to the set of default bindings, instead of replacing
Expand Down Expand Up @@ -2249,11 +2261,14 @@ <h2>Addons</h2>
succeeded. See the <a href="../demo/loadmode.html">demo</a>.</dd>

<dt id="addon_continuecomment"><a href="../addon/comment/continuecomment.js"><code>comment/continuecomment.js</code></a></dt>
<dd>Adds an <code>continueComments</code> option, which can be
set to true to have the editor prefix new lines inside C-like
block comments with an asterisk when Enter is pressed. It can
also be set to a string in order to bind this functionality to a
specific key..</dd>
<dd>Adds a <code>continueComments</code> option, which sets whether the
editor will make the next line continue a comment when you press Enter
inside a comment block. Can be set to a boolean to enable/disable this
functionality. Set to a string, it will continue comments using a custom
shortcut. Set to an object, it will use the <code>key</code> property for
a custom shortcut and the boolean <code>continueLineComment</code>
property to determine whether single-line comments should be continued
(defaulting to <code>true</code>).</dd>

<dt id="addon_placeholder"><a href="../addon/display/placeholder.js"><code>display/placeholder.js</code></a></dt>
<dd>Adds a <code>placeholder</code> option that can be used to
Expand All @@ -2269,6 +2284,16 @@ <h2>Addons</h2>
on <a href="../addon/display/fullscreen.css"><code>fullscreen.css</code></a>. <a href="../demo/fullscreen.html">Demo
here</a>.</dd>

<dt id="addon_rulers"><a href="../addon/display/rulers.js"><code>display/rulers.js</code></a></dt>
<dd>Adds a <code>rulers</code> option, which can be used to show
one or more vertical rulers in the editor. The option, if
defined, should be given an array of <code>{column,
className}</code> objects or numbers. The ruler will be
displayed at the column indicated by the number or
the <code>column</code> property. The <code>className</code>
property can be used to assign a custom style to a
ruler. <a href="../demo/rulers.html">Demo here</a>.</dd>

<dt id="addon_hardwrap"><a href="../addon/wrap/hardwrap.js"><code>wrap/hardwrap.js</code></a></dt>
<dd>Addon to perform hard line wrapping/breaking for paragraphs
of text. Adds these methods to editor instances:
Expand Down
4 changes: 4 additions & 0 deletions doc/realworld.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="http://buzz.blogger.com/2013/04/improvements-to-blogger-template-html.html">Blogger's template editor</a></li>
<li><a href="http://bluegriffon.org/">BlueGriffon</a> (HTML editor)</li>
<li><a href="http://cargocollective.com/">Cargo Collective</a> (creative publishing platform)</li>
<li><a href="https://developers.google.com/chrome-developer-tools/">Chrome DevTools</a></li>
<li><a href="http://clickhelp.co/">ClickHelp</a> (technical writing tool)</li>
<li><a href="http://complete-ly.appspot.com/playground/code.playground.html">Complete.ly playground</a></li>
<li><a href="http://drupal.org/project/cpn">Code per Node</a> (Drupal module)</li>
Expand Down Expand Up @@ -63,6 +64,7 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="https://metacpan.org/module/Farabi">Farabi</a> (modern Perl IDE)</li>
<li><a href="http://blog.pamelafox.org/2012/02/interactive-html5-slides-with-fathomjs.html">FathomJS integration</a> (slides with editors, again)</li>
<li><a href="http://fiddlesalad.com/">Fiddle Salad</a> (web development environment)</li>
<li><a href="https://hacks.mozilla.org/2013/11/firefox-developer-tools-episode-27-edit-as-html-codemirror-more/">Firefox Developer Tools</a></li>
<li><a href="http://www.firepad.io">Firepad</a> (collaborative text editor)</li>
<li><a href="https://code.google.com/p/gerrit/">Gerrit</a>'s diff view</a></li>
<li><a href="http://tour.golang.org">Go language tour</a></li>
Expand All @@ -74,6 +76,7 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="http://haxpad.com/">HaxPad</a> (editor for Win RT)</li>
<li><a href="http://megafonweblab.github.com/histone-javascript/">Histone template engine playground</a></li>
<li><a href="http://icecoder.net">ICEcoder</a> (web IDE)</li>
<li><a href="http://i-mos.org/imos/">i-MOS</a> (modeling and simulation platform)</li>
<li><a href="http://www.janvas.com/">Janvas</a> (vector graphics editor)</li>
<li><a href="http://extensions.joomla.org/extensions/edition/editors/8723">Joomla plugin</a></li>
<li><a href="http://jqfundamentals.com/">jQuery fundamentals</a> (interactive tutorial)</li>
Expand All @@ -83,6 +86,7 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="http://jumpseller.com/">Jumpseller</a> (online store builder)</li>
<li><a href="http://kl1p.com/cmtest/1">kl1p</a> (paste service)</li>
<li><a href="http://kodtest.com/">Kodtest</a> (HTML/JS/CSS playground)</li>
<li><a href="https://laborate.io/">Laborate</a> (collaborative coding)</li>
<li><a href="http://lighttable.com/">Light Table</a> (experimental IDE)</li>
<li><a href="http://liveweave.com/">Liveweave</a> (HTML/CSS/JS scratchpad)</li>
<li><a href="http://marklighteditor.com/">Marklight editor</a> (lightweight markup editor)</li>
Expand Down
13 changes: 12 additions & 1 deletion doc/releases.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ <h2>Release notes and version history</h2>

<h2>Version 3.x</h2>

<p class="rel">21-11-2013: <a href="http://codemirror.net/codemirror-3.21.zip">Version 3.21</a>:</p>
<p class="rel">21-02-2014: <a href="http://codemirror.net/codemirror-3.22.zip">Version 3.22</a>:</p>

<ul class="rel-note">
<li>Adds the <a href="doc/manual.html#findMarks"><code>findMarks</code></a> method.</li>
<li>New addons: <a href="doc/manual.html#addon_rulers">rulers</a>, markdown-fold, yaml-lint.</li>
<li>New theme: <a href="demo/theme.html?mdn-like">mdn-like</a>.</li>
<li>New mode: <a href="mode/sold/index.html">Sold</a>.</li>
<li>Full <a href="https://github.com/marijnh/CodeMirror/compare/3.21.0...3.22.0">list of patches</a>.</li>
</ul>

<p class="rel">16-01-2014: <a href="http://codemirror.net/codemirror-3.21.zip">Version 3.21</a>:</p>

<ul class="rel-note">
<li>Auto-indenting a block will no longer add trailing whitespace to blank lines.</a>
Expand All @@ -39,6 +49,7 @@ <h2>Version 3.x</h2>
<li>Make it possible to fetch multiple applicable helper values with <a href="manual.html#getHelpers"><code>getHelpers</code></a>, and to register helpers matched on predicates with <a href="manual.html#registerGlobalHelper"><code>registerGlobalHelper</code></a>.</li>
<li>New theme <a href="../demo/theme.html?pastel-on-dark">pastel-on-dark</a>.</li>
<li>Better ECMAScript 6 support in <a href="../mode/javascript/index.html">JavaScript</a> mode.</li>
<li>Full <a href="https://github.com/marijnh/CodeMirror/compare/3.20.0...3.21.0">list of patches</a>.</li>
</ul>

<p class="rel">21-11-2013: <a href="http://codemirror.net/codemirror-3.20.zip">Version 3.20</a>:</p>
Expand Down
13 changes: 7 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<p><strong>CodeMirror</strong> is a versatile text editor
implemented in JavaScript for the browser. It is specialized for
editing code, and comes with a number of language modes and addons
that implement more advanced editing functionaly.</p>
that implement more advanced editing functionality.</p>

<p>A rich <a href="doc/manual.html#api">programming API</a> and a
CSS <a href="doc/manual.html#styling">theming</a> system are
Expand Down Expand Up @@ -84,7 +84,7 @@ <h2>This is CodeMirror</h2>
</script>
<div style="position: relative; margin: 1em 0;">
<a class="bigbutton left" href="http://codemirror.net/codemirror.zip">DOWNLOAD LATEST RELEASE</a>
<div><strong>version 3.21</strong> (<a href="doc/releases.html">Release notes</a>)</div>
<div><strong>version 3.22</strong> (<a href="doc/releases.html">Release notes</a>)</div>
<div>or use the <a href="doc/compress.html">minification helper</a></div>
<div style="position: absolute; top: 0; right: 0; text-align: right">
<span class="bigbutton right" onclick="document.getElementById('paypal').submit();">DONATE WITH PAYPAL</span>
Expand Down Expand Up @@ -141,11 +141,12 @@ <h2>Features</h2>
<h2>Community</h2>

<p>CodeMirror is an open-source project shared under
an <a href="LICENSE">MIT license</a>. It is the editor used in
<a href="http://www.chris-granger.com/2012/04/12/light-table---a-new-ide-concept/">Light
an <a href="LICENSE">MIT license</a>. It is the editor used in the
dev tools for
both <a href="https://hacks.mozilla.org/2013/11/firefox-developer-tools-episode-27-edit-as-html-codemirror-more/">Firefox</a>
and <a href="https://developers.google.com/chrome-developer-tools/">Chrome</a>, <a href="http://www.lighttable.com/">Light
Table</a>, <a href="http://brackets.io/">Adobe
Brackets</a>, <a href="https://script.google.com/">Google Apps
Script</a>, <a href="http://blog.bitbucket.org/2013/05/14/edit-your-code-in-the-cloud-with-bitbucket/">Bitbucket</a>,
Brackets</a>, <a href="http://blog.bitbucket.org/2013/05/14/edit-your-code-in-the-cloud-with-bitbucket/">Bitbucket</a>,
and <a href="doc/realworld.html">many other projects</a>.</p>

<p>Development and bug tracking happens
Expand Down
180 changes: 126 additions & 54 deletions keymap/vim.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
{ keys: ['<S-BS>'], type: 'keyToKey', toKeys: ['b'] },
{ keys: ['<C-n>'], type: 'keyToKey', toKeys: ['j'] },
{ keys: ['<C-p>'], type: 'keyToKey', toKeys: ['k'] },
{ keys: ['C-['], type: 'keyToKey', toKeys: ['<Esc>'] },
{ keys: ['<C-[>'], type: 'keyToKey', toKeys: ['<Esc>'] },
{ keys: ['<C-c>'], type: 'keyToKey', toKeys: ['<Esc>'] },
{ keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'], context: 'normal' },
{ keys: ['s'], type: 'keyToKey', toKeys: ['x', 'i'], context: 'visual'},
Expand Down Expand Up @@ -1457,7 +1457,7 @@
motionArgs.selectedCharacter);
var increment = motionArgs.forward ? -1 : 1;
recordLastCharacterSearch(increment, motionArgs);
if(!curEnd)return cm.getCursor();
if (!curEnd) return null;
curEnd.ch += increment;
return curEnd;
},
Expand Down Expand Up @@ -1532,22 +1532,44 @@
ch: findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)) };
},
textObjectManipulation: function(cm, motionArgs) {
// TODO: lots of possible exceptions that can be thrown here. Try da(
// outside of a () block.

// TODO: adding <> >< to this map doesn't work, presumably because
// they're operators
var mirroredPairs = {'(': ')', ')': '(',
'{': '}', '}': '{',
'[': ']', ']': '['};
var selfPaired = {'\'': true, '"': true};

var character = motionArgs.selectedCharacter;

// Inclusive is the difference between a and i
// TODO: Instead of using the additional text object map to perform text
// object operations, merge the map into the defaultKeyMap and use
// motionArgs to define behavior. Define separate entries for 'aw',
// 'iw', 'a[', 'i[', etc.
var inclusive = !motionArgs.textObjectInner;
if (!textObjects[character]) {

var tmp;
if (mirroredPairs[character]) {
tmp = selectCompanionObject(cm, mirroredPairs[character], inclusive);
} else if (selfPaired[character]) {
tmp = findBeginningAndEnd(cm, character, inclusive);
} else if (character === 'W') {
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
true /** bigWord */);
} else if (character === 'w') {
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
false /** bigWord */);
} else {
// No text object defined for this, don't move.
return null;
}
var tmp = textObjects[character](cm, inclusive);
var start = tmp.start;
var end = tmp.end;
return [start, end];

return [tmp.start, tmp.end];
},

repeatLastCharacterSearch: function(cm, motionArgs) {
var lastSearch = vimGlobalState.lastChararacterSearch;
var repeat = motionArgs.repeat;
Expand Down Expand Up @@ -2015,36 +2037,6 @@
}
};

var textObjects = {
// TODO: lots of possible exceptions that can be thrown here. Try da(
// outside of a () block.
// TODO: implement text objects for the reverse like }. Should just be
// an additional mapping after moving to the defaultKeyMap.
'w': function(cm, inclusive) {
return expandWordUnderCursor(cm, inclusive, true /** forward */,
false /** bigWord */);
},
'W': function(cm, inclusive) {
return expandWordUnderCursor(cm, inclusive,
true /** forward */, true /** bigWord */);
},
'{': function(cm, inclusive) {
return selectCompanionObject(cm, '}', inclusive);
},
'(': function(cm, inclusive) {
return selectCompanionObject(cm, ')', inclusive);
},
'[': function(cm, inclusive) {
return selectCompanionObject(cm, ']', inclusive);
},
'\'': function(cm, inclusive) {
return findBeginningAndEnd(cm, "'", inclusive);
},
'"': function(cm, inclusive) {
return findBeginningAndEnd(cm, '"', inclusive);
}
};

/*
* Below are miscellaneous utility functions used by vim.js
*/
Expand Down Expand Up @@ -2634,13 +2626,25 @@
return cur;
}

// TODO: perhaps this finagling of start and end positions belonds
// in codmirror/replaceRange?
function selectCompanionObject(cm, revSymb, inclusive) {
var cur = cm.getCursor();

var end = findMatchedSymbol(cm, cur, revSymb);
var start = findMatchedSymbol(cm, end);
start.ch += inclusive ? 1 : 0;
end.ch += inclusive ? 0 : 1;

if((start.line == end.line && start.ch > end.ch)
|| (start.line > end.line)) {
var tmp = start;
start = end;
end = tmp;
}

if(inclusive) {
end.ch += 1;
} else {
start.ch += 1;
}

return { start: start, end: end };
}
Expand Down Expand Up @@ -2750,10 +2754,84 @@
if (!escapeNextChar && c == '/') {
slashes.push(i);
}
escapeNextChar = (c == '\\');
escapeNextChar = !escapeNextChar && (c == '\\');
}
return slashes;
}

// Translates a search string from ex (vim) syntax into javascript form.
function fixRegex(str) {
// When these match, add a '\' if unescaped or remove one if escaped.
var specials = ['|', '(', ')', '{'];
// Remove, but never add, a '\' for these.
var unescape = ['}'];
var escapeNextChar = false;
var out = [];
for (var i = -1; i < str.length; i++) {
var c = str.charAt(i) || '';
var n = str.charAt(i+1) || '';
var specialComesNext = (specials.indexOf(n) != -1);
if (escapeNextChar) {
if (c !== '\\' || !specialComesNext) {
out.push(c);
}
escapeNextChar = false;
} else {
if (c === '\\') {
escapeNextChar = true;
// Treat the unescape list as special for removing, but not adding '\'.
if (unescape.indexOf(n) != -1) {
specialComesNext = true;
}
// Not passing this test means removing a '\'.
if (!specialComesNext || n === '\\') {
out.push(c);
}
} else {
out.push(c);
if (specialComesNext && n !== '\\') {
out.push('\\');
}
}
}
}
return out.join('');
}

// Translates the replace part of a search and replace from ex (vim) syntax into
// javascript form. Similar to fixRegex, but additionally fixes back references
// (translates '\[0..9]' to '$[0..9]') and follows different rules for escaping '$'.
function fixRegexReplace(str) {
var escapeNextChar = false;
var out = [];
for (var i = -1; i < str.length; i++) {
var c = str.charAt(i) || '';
var n = str.charAt(i+1) || '';
if (escapeNextChar) {
out.push(c);
escapeNextChar = false;
} else {
if (c === '\\') {
escapeNextChar = true;
if ((isNumber(n) || n === '$')) {
out.push('$');
} else if (n !== '/' && n !== '\\') {
out.push('\\');
}
} else {
if (c === '$') {
out.push('$');
}
out.push(c);
if (n === '/') {
out.push('\\');
}
}
}
}
return out.join('');
}

/**
* Extract the regular expression from the query and return a Regexp object.
* Returns null if the query is blank.
Expand Down Expand Up @@ -2785,6 +2863,7 @@
if (!regexPart) {
return null;
}
regexPart = fixRegex(regexPart);
if (smartCase) {
ignoreCase = (/^[^A-Z]*$/).test(regexPart);
}
Expand Down Expand Up @@ -3279,6 +3358,7 @@
var confirm = false; // Whether to confirm each replace.
if (slashes[1]) {
replacePart = argString.substring(slashes[1] + 1, slashes[2]);
replacePart = fixRegexReplace(replacePart);
}
if (slashes[2]) {
// After the 3rd slash, we can have flags followed by a space followed
Expand Down Expand Up @@ -3495,18 +3575,10 @@
* Shift + key modifier to the resulting letter, while preserving other
* modifers.
*/
// TODO: Figure out a way to catch capslock.
function cmKeyToVimKey(key, modifier) {
var vimKey = key;
if (isUpperCase(vimKey)) {
// Convert to lower case if shift is not the modifier since the key
// we get from CodeMirror is always upper case.
if (modifier == 'Shift') {
modifier = null;
}
else {
if (isUpperCase(vimKey) && modifier == 'Ctrl') {
vimKey = vimKey.toLowerCase();
}
}
if (modifier) {
// Vim will parse modifier+key combination as a single key.
Expand All @@ -3532,9 +3604,9 @@
function bindKeys(keys, modifier) {
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!modifier && inArray(key, specialSymbols)) {
// Wrap special symbols with '' because that's how CodeMirror binds
// them.
if (!modifier && key.length == 1) {
// Wrap all keys without modifiers with '' to identify them by their
// key characters instead of key identifiers.
key = "'" + key + "'";
}
var vimKey = cmKeyToVimKey(keys[i], modifier);
Expand All @@ -3543,7 +3615,7 @@
}
}
bindKeys(upperCaseAlphabet);
bindKeys(upperCaseAlphabet, 'Shift');
bindKeys(lowerCaseAlphabet);
bindKeys(upperCaseAlphabet, 'Ctrl');
bindKeys(specialSymbols);
bindKeys(specialSymbols, 'Ctrl');
Expand Down
23 changes: 12 additions & 11 deletions lib/codemirror.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
min-width: 20px;
text-align: right;
color: #999;
-moz-box-sizing: content-box;
box-sizing: content-box;
}

/* CURSOR */
Expand All @@ -59,6 +61,11 @@

.cm-tab { display: inline-block; }

.CodeMirror-ruler {
border-left: 1px solid #ccc;
position: absolute;
}

/* DEFAULT THEME */

.cm-s-default .cm-keyword {color: #708;}
Expand Down Expand Up @@ -114,7 +121,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px; padding-right: 30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
Expand All @@ -123,6 +130,9 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
-moz-box-sizing: content-box;
box-sizing: content-box;
}

/* The fake, visible scrollbars. Used to force redraw during scrolling
Expand Down Expand Up @@ -197,16 +207,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-code pre {
border-right: 30px solid transparent;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
.CodeMirror-wrap .CodeMirror-code pre {
border-right: none;
width: auto;
}

.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
Expand Down
130 changes: 87 additions & 43 deletions lib/codemirror.js

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions mode/clojure/clojure.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
* Author: Hans Engel
* Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)
*/
CodeMirror.defineMode("clojure", function () {
CodeMirror.defineMode("clojure", function (options) {
var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2",
ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword";
var INDENT_WORD_SKIP = 2;
var INDENT_WORD_SKIP = options.indentUnit || 2;
var NORMAL_INDENT_UNIT = options.indentUnit || 2;

function makeKeywords(str) {
var obj = {}, words = str.split(" ");
Expand Down Expand Up @@ -44,7 +45,7 @@ CodeMirror.defineMode("clojure", function () {
sign: /[+-]/,
exponent: /e/i,
keyword_char: /[^\s\(\[\;\)\]]/,
symbol: /[\w*+!\-\._?:\/]/
symbol: /[\w*+!\-\._?:<>\/]/
};

function stateStack(indent, type, prev) { // represents a state stack object
Expand Down Expand Up @@ -179,8 +180,8 @@ CodeMirror.defineMode("clojure", function () {
stream.eatSpace();
if (stream.eol() || stream.peek() == ";") {
// nothing significant after
// we restart indentation 1 space after
pushStack(state, indentTemp + 1, ch);
// we restart indentation the user defined spaces after
pushStack(state, indentTemp + NORMAL_INDENT_UNIT, ch);
} else {
pushStack(state, indentTemp + stream.current().length, ch); // else we match
}
Expand Down
28 changes: 19 additions & 9 deletions mode/css/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return pushContext(state, stream, "media");
} else if (type == "@font-face") {
return "font_face_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
return "keyframes";
} else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at");
} else if (type == "hash") {
Expand Down Expand Up @@ -264,6 +266,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return "font_face";
};

states.keyframes = function(type, stream, state) {
if (type == "word") { override = "variable"; return "keyframes"; }
if (type == "{") return pushContext(state, stream, "top");
return pass(type, stream, state);
};

states.at = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state);
Expand Down Expand Up @@ -308,6 +316,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
indent: function(state, textAfter) {
var cx = state.context, ch = textAfter && textAfter.charAt(0);
var indent = cx.indent;
if (cx.type == "prop" && ch == "}") cx = cx.prev;
if (cx.prev &&
(ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
ch == ")" && (cx.type == "parens" || cx.type == "params" || cx.type == "media_parens") ||
Expand Down Expand Up @@ -353,10 +362,10 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
var propertyKeywords_ = [
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-iteration-count",
"animation-name", "animation-play-state", "animation-timing-function",
"appearance", "azimuth", "backface-visibility", "background",
"background-attachment", "background-clip", "background-color",
"animation-direction", "animation-duration", "animation-fill-mode",
"animation-iteration-count", "animation-name", "animation-play-state",
"animation-timing-function", "appearance", "azimuth", "backface-visibility",
"background", "background-attachment", "background-clip", "background-color",
"background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
Expand Down Expand Up @@ -387,10 +396,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid-cell", "grid-column", "grid-column-align",
"grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow",
"grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span",
"grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens",
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
"grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
"grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
"grid-template", "grid-template-areas", "grid-template-columns",
"grid-template-rows", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
Expand Down Expand Up @@ -667,7 +677,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
}
},
"@": function(stream) {
if (stream.match(/^(charset|document|font-face|import|keyframes|media|namespace|page|supports)\b/, false)) return false;
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
Expand Down
1 change: 0 additions & 1 deletion mode/eiffel/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,6 @@ <h2>Eiffel mode</h2>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: "text/x-eiffel",
tabMode: "indent",
indentUnit: 4,
lineNumbers: true,
theme: "neat"
Expand Down
2 changes: 1 addition & 1 deletion mode/gas/gas.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) {
});
}

var arch = parserConfig.architecture.toLowerCase();
var arch = (parserConfig.architecture || "x86").toLowerCase();
if (arch === "x86") {
x86(parserConfig);
} else if (arch === "arm" || arch === "armv6") {
Expand Down
4 changes: 1 addition & 3 deletions mode/htmlembedded/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ <h2>Html Embedded Scripts mode</h2>
lineNumbers: true,
mode: "application/x-ejs",
indentUnit: 4,
indentWithTabs: true,
enterMode: "keep",
tabMode: "shift"
indentWithTabs: true
});
</script>

Expand Down
5 changes: 4 additions & 1 deletion mode/htmlmixed/htmlmixed.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
var htmlMode = CodeMirror.getMode(config, {name: "xml",
htmlMode: true,
multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
var cssMode = CodeMirror.getMode(config, "css");

var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
Expand Down
2 changes: 1 addition & 1 deletion mode/htmlmixed/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ <h1>Mixed HTML Example</h1>
{matches: /(text|application)\/(x-)?vb(a|script)/i,
mode: "vbscript"}]
};
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: mixedMode, tabMode: "indent"});
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: mixedMode});
</script>

<p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
Expand Down
2 changes: 2 additions & 0 deletions mode/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ <h2>Language modes</h2>
<li><a href="php/index.html">PHP</a></li>
<li><a href="pig/index.html">Pig Latin</a></li>
<li><a href="properties/index.html">Properties files</a></li>
<li><a href="puppet/index.html">Puppet</a></li>
<li><a href="python/index.html">Python</a></li>
<li><a href="q/index.html">Q</a></li>
<li><a href="r/index.html">R</a></li>
Expand All @@ -93,6 +94,7 @@ <h2>Language modes</h2>
<li><a href="smalltalk/index.html">Smalltalk</a></li>
<li><a href="smarty/index.html">Smarty</a></li>
<li><a href="smartymixed/index.html">Smarty/HTML mixed</a></li>
<li><a href="solr/index.html">Solr</a></li>
<li><a href="sql/index.html">SQL</a> (several dialects)</li>
<li><a href="sparql/index.html">SPARQL</a></li>
<li><a href="stex/index.html">sTeX, LaTeX</a></li>
Expand Down
8 changes: 5 additions & 3 deletions mode/javascript/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,13 @@ <h2>JavaScript mode</h2>
</script>

<p>
JavaScript mode supports a two configuration
options:
JavaScript mode supports several configuration options:
<ul>
<li><code>json</code> which will set the mode to expect JSON
data rather than a JavaScript program.</li>
<li><code>jsonld</code> which will set the mode to expect
<a href="http://json-ld.org">JSON-LD</a> linked data rather
than a JavaScript program (<a href="json-ld.html">demo</a>).</li>
<li><code>typescript</code> which will activate additional
syntax highlighting and some other things for TypeScript code
(<a href="typescript.html">demo</a>).</li>
Expand All @@ -103,5 +105,5 @@ <h2>JavaScript mode</h2>
</ul>
</p>

<p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>, <code>text/typescript</code>, <code>application/typescript</code>.</p>
<p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>, <code>application/ld+json</code>, <code>text/typescript</code>, <code>application/typescript</code>.</p>
</article>
14 changes: 11 additions & 3 deletions mode/javascript/javascript.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var statementIndent = parserConfig.statementIndent;
var jsonMode = parserConfig.json;
var jsonldMode = parserConfig.jsonld;
var jsonMode = parserConfig.json || jsonldMode;
var isTS = parserConfig.typescript;

// Tokenizer
Expand Down Expand Up @@ -53,6 +54,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}();

var isOperatorChar = /[+\-*&%=<>!?|~^]/;
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;

function readRegexp(stream) {
var escaped = false, next, inSet = false;
Expand Down Expand Up @@ -128,6 +130,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next;
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
state.tokenize = tokenBase;
return ret("jsonld-keyword", "meta");
}
while ((next = stream.next()) != null) {
if (next == quote && !escaped) break;
escaped = !escaped && next == "\\";
Expand Down Expand Up @@ -195,7 +201,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {

// Parser

var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true};
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};

function JSLexical(indented, column, type, align, prev, info) {
this.indented = indented;
Expand Down Expand Up @@ -408,7 +414,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
} else if (type == "number" || type == "string") {
cx.marked = type + " property";
cx.marked = jsonldMode ? "property" : (type + " property");
} else if (type == "[") {
return cont(expression, expect("]"), afterprop);
}
Expand Down Expand Up @@ -616,6 +622,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
fold: "brace",

helperType: jsonMode ? "json" : "javascript",
jsonldMode: jsonldMode,
jsonMode: jsonMode
};
});
Expand All @@ -626,5 +633,6 @@ CodeMirror.defineMIME("application/javascript", "javascript");
CodeMirror.defineMIME("application/ecmascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
72 changes: 72 additions & 0 deletions mode/javascript/json-ld.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!doctype html>

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

<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="../../addon/comment/continuecomment.js"></script>
<script src="../../addon/comment/comment.js"></script>
<script src="javascript.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id="nav">
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"/></a>

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

<article>
<h2>JSON-LD mode</h2>


<div><textarea id="code" name="code">
{
"@context": {
"name": "http://schema.org/name",
"description": "http://schema.org/description",
"image": {
"@id": "http://schema.org/image",
"@type": "@id"
},
"geo": "http://schema.org/geo",
"latitude": {
"@id": "http://schema.org/latitude",
"@type": "xsd:float"
},
"longitude": {
"@id": "http://schema.org/longitude",
"@type": "xsd:float"
},
"xsd": "http://www.w3.org/2001/XMLSchema#"
},
"name": "The Empire State Building",
"description": "The Empire State Building is a 102-story landmark in New York City.",
"image": "http://www.civil.usherbrooke.ca/cours/gci215a/empire-state-building.jpg",
"geo": {
"latitude": "40.75",
"longitude": "73.98"
}
}
</textarea></div>

<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
matchBrackets: true,
autoCloseBrackets: true,
mode: "application/ld+json",
lineWrapping: true
});
</script>

<p>This is a specialization of the <a href="index.html">JavaScript mode</a>.</p>
</article>
38 changes: 38 additions & 0 deletions mode/javascript/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,42 @@

MT("scary_regexp",
"[string-2 /foo[[/]]bar/];");

var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2},
{name: "javascript", jsonld: true}
);
function LD(name) {
test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1));
}

LD("json_ld_keywords",
'{',
' [meta "@context"]: {',
' [meta "@base"]: [string "http://example.com"],',
' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],',
' [property "likesFlavor"]: {',
' [meta "@container"]: [meta "@list"]',
' [meta "@reverse"]: [string "@beFavoriteOf"]',
' },',
' [property "nick"]: { [meta "@container"]: [meta "@set"] },',
' [property "nick"]: { [meta "@container"]: [meta "@index"] }',
' },',
' [meta "@graph"]: [[ {',
' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],',
' [property "name"]: [string "John Lennon"],',
' [property "modified"]: {',
' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],',
' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]',
' }',
' } ]]',
'}');

LD("json_ld_fake",
'{',
' [property "@fake"]: [string "@fake"],',
' [property "@contextual"]: [string "@identifier"],',
' [property "user@domain.com"]: [string "@graphical"],',
' [property "@ID"]: [string "@@ID"]',
'}');
})();
1 change: 0 additions & 1 deletion mode/julia/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ <h2>Julia mode</h2>
},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift",
matchBrackets: true
});
</script>
Expand Down
70 changes: 47 additions & 23 deletions mode/julia/julia.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
return new RegExp("^((" + words.join(")|(") + "))\\b");
}

var operators = parserConf.operators || /^(?:\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|<:|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b|\.{3})/;
var operators = parserConf.operators || /^\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b/;
var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*!*/;
var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch"];
var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch", "do"];
var blockClosers = ["end", "else", "elseif", "catch", "finally"];
var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall'];
var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf'];
var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf'];

//var stringPrefixes = new RegExp("^[br]?('|\")")
var stringPrefixes = /^[br]?('|"{3}|")/;
var stringPrefixes = /^(`|'|"{3}|([br]?"))/;
var keywords = wordRegexp(keywordList);
var builtins = wordRegexp(builtinList);
var openers = wordRegexp(blockOpeners);
var closers = wordRegexp(blockClosers);
var macro = /@[_A-Za-z][_A-Za-z0-9]*!*/;
var macro = /^@[_A-Za-z][_A-Za-z0-9]*/;
var symbol = /^:[_A-Za-z][_A-Za-z0-9]*/;
var indentInfo = null;

function in_array(state) {
Expand All @@ -43,14 +44,19 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
function tokenBase(stream, state) {
// Handle scope changes
var leaving_expr = state.leaving_expr;
if(stream.sol()) {
leaving_expr = false;
}
state.leaving_expr = false;
if(leaving_expr) {
if(stream.match(/^'+/)) {
return 'operator';
}
if(stream.match("...")) {
return 'operator';
}

}

if(stream.match(/^\.{2,3}/)) {
return 'operator';
}

if (stream.eatSpace()) {
Expand Down Expand Up @@ -83,8 +89,12 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
state.leaving_expr=true;
}

if(ch===')') {
state.leaving_expr = true;
}

var match;
if(match=stream.match(openers, false)) {
if(!in_array(state) && (match=stream.match(openers, false))) {
state.scopes.push(match);
}

Expand All @@ -93,25 +103,29 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
}

if(in_array(state)) {
if(stream.match("end")) {
if(stream.match(/^end/)) {
return 'number';
}

}
if(stream.match("=>")) {

if(stream.match(/^=>/)) {
return 'operator';
}


// Handle Number Literals
if (stream.match(/^[0-9\.]/, false)) {
var imMatcher = RegExp(/^im\b/);
var floatLiteral = false;
// Floats
if (stream.match(/^\d*\.\d+([ef][\+\-]?\d+)?/i)) { floatLiteral = true; }
if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
if (stream.match(/^\d*\.(?!\.)\d+([ef][\+\-]?\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.match(imMatcher);
state.leaving_expr = true;
return 'number';
}
// Integers
Expand All @@ -124,31 +138,44 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
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.match(imMatcher);
state.leaving_expr = true;
return 'number';
}
}

if(stream.match(/^(::)|(<:)/)) {
return 'operator';
}

// Handle symbols
if(!leaving_expr && stream.match(symbol)) {
return 'string';
}

// Handle operators and Delimiters
if (stream.match(operators)) {
return 'operator';
}


// Handle Strings
if (stream.match(stringPrefixes)) {
state.tokenize = tokenStringFactory(stream.current());
return state.tokenize(stream, state);
}

// Handle operators and Delimiters
if (stream.match(operators)) {
return 'operator';
if (stream.match(macro)) {
return 'meta';
}


if (stream.match(delimiters)) {
return null;
}
Expand All @@ -161,9 +188,6 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
return 'builtin';
}

if (stream.match(macro)) {
return 'meta';
}

if (stream.match(identifiers)) {
state.leaving_expr=true;
Expand Down Expand Up @@ -248,7 +272,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
if(textAfter=="end" || textAfter=="]" || textAfter=="}" || textAfter=="else" || textAfter=="elseif" || textAfter=="catch" || textAfter=="finally") {
delta = -1;
}
return (state.scopes.length + delta) * 2;
return (state.scopes.length + delta) * 4;
},

lineComment: "#",
Expand Down
2 changes: 1 addition & 1 deletion mode/livescript/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,6 @@ <h2>LiveScript mode</h2>

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

<p>The LiveScript mode was written by Kenneth Bentley (<a href="LICENSE">license</a>).</p>
<p>The LiveScript mode was written by Kenneth Bentley.</p>

</article>
1 change: 0 additions & 1 deletion mode/lua/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ <h2>Lua mode</h2>
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
tabMode: "indent",
matchBrackets: true,
theme: "neat"
});
Expand Down
8 changes: 5 additions & 3 deletions mode/markdown/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
styles.push(formatting + "-" + state.formatting[i]);

if (state.formatting[i] === "header") {
styles.push(formatting + "-" + state.formatting[i] + state.header);
styles.push(formatting + "-" + state.formatting[i] + "-" + state.header);
}

// Add `formatting-quote` and `formatting-quote-#` for blockquotes
Expand Down Expand Up @@ -275,7 +275,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

if (state.code) { styles.push(code); }

if (state.header) { styles.push(header); styles.push(header + state.header); }
if (state.header) { styles.push(header); styles.push(header + "-" + state.header); }

if (state.quote) {
styles.push(quote);
Expand Down Expand Up @@ -738,7 +738,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

blankLine: blankLine,

getType: getType
getType: getType,

fold: "markdown"
};
return mode;
}, "xml");
Expand Down
30 changes: 15 additions & 15 deletions mode/markdown/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
"[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");

FT("formatting_atxHeader",
"[header&header1&formatting&formatting-header&formatting-header1 #][header&header1 foo # bar ][header&header1&formatting&formatting-header&formatting-header1 #]");
"[header&header-1&formatting&formatting-header&formatting-header-1 #][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");

FT("formatting_setextHeader",
"foo",
"[header&header1&formatting&formatting-header&formatting-header1 =]");
"[header&header-1&formatting&formatting-header&formatting-header-1 =]");

FT("formatting_blockquote",
"[quote&quote-1&formatting&formatting-quote&formatting-quote-1 > ][quote&quote-1 foo]");
Expand Down Expand Up @@ -138,31 +138,31 @@
// http://daringfireball.net/projects/markdown/syntax#header

MT("atxH1",
"[header&header1 # foo]");
"[header&header-1 # foo]");

MT("atxH2",
"[header&header2 ## foo]");
"[header&header-2 ## foo]");

MT("atxH3",
"[header&header3 ### foo]");
"[header&header-3 ### foo]");

MT("atxH4",
"[header&header4 #### foo]");
"[header&header-4 #### foo]");

MT("atxH5",
"[header&header5 ##### foo]");
"[header&header-5 ##### foo]");

MT("atxH6",
"[header&header6 ###### foo]");
"[header&header-6 ###### foo]");

// H6 - 7x '#' should still be H6, per Dingus
// http://daringfireball.net/projects/markdown/dingus
MT("atxH6NotH7",
"[header&header6 ####### foo]");
"[header&header-6 ####### foo]");

// Inline styles should be parsed inside headers
MT("atxH1inline",
"[header&header1 # foo ][header&header1&em *bar*]");
"[header&header-1 # foo ][header&header-1&em *bar*]");

// Setext headers - H1, H2
// Per documentation, "Any number of underlining =’s or -’s will work."
Expand All @@ -174,22 +174,22 @@
// Check if single underlining = works
MT("setextH1",
"foo",
"[header&header1 =]");
"[header&header-1 =]");

// Check if 3+ ='s work
MT("setextH1",
"foo",
"[header&header1 ===]");
"[header&header-1 ===]");

// Check if single underlining - works
MT("setextH2",
"foo",
"[header&header2 -]");
"[header&header-2 -]");

// Check if 3+ -'s work
MT("setextH2",
"foo",
"[header&header2 ---]");
"[header&header-2 ---]");

// Single-line blockquote with trailing space
MT("blockquoteSpace",
Expand Down Expand Up @@ -278,7 +278,7 @@

// List after header
MT("listAfterHeader",
"[header&header1 # foo]",
"[header&header-1 # foo]",
"[variable-2 - bar]");

// Formatting in lists (*)
Expand Down
3 changes: 3 additions & 0 deletions mode/meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ CodeMirror.modeInfo = [
{name: 'JavaScript', mime: 'text/javascript', mode: 'javascript'},
{name: 'JSON', mime: 'application/x-json', mode: 'javascript'},
{name: 'JSON', mime: 'application/json', mode: 'javascript'},
{name: 'JSON-LD', mime: 'application/ld+json', mode: 'javascript'},
{name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'},
{name: 'Jinja2', mime: null, mode: 'jinja2'},
{name: 'Julia', mime: 'text/x-julia', mode: 'julia'},
Expand All @@ -57,6 +58,7 @@ CodeMirror.modeInfo = [
{name: 'Plain Text', mime: 'text/plain', mode: 'null'},
{name: 'Properties files', mime: 'text/x-properties', mode: 'properties'},
{name: 'Python', mime: 'text/x-python', mode: 'python'},
{name: 'Puppet', mime: 'text/x-puppet', mode: 'puppet'},
{name: 'Cython', mime: 'text/x-cython', mode: 'python'},
{name: 'R', mime: 'text/x-rsrc', mode: 'r'},
{name: 'reStructuredText', mime: 'text/x-rst', mode: 'rst'},
Expand All @@ -70,6 +72,7 @@ CodeMirror.modeInfo = [
{name: 'Smalltalk', mime: 'text/x-stsrc', mode: 'smalltalk'},
{name: 'Smarty', mime: 'text/x-smarty', mode: 'smarty'},
{name: 'SmartyMixed', mime: 'text/x-smarty', mode: 'smartymixed'},
{name: 'Solr', mime: 'text/x-solr', mode: 'solr'},
{name: 'SPARQL', mime: 'application/x-sparql-query', mode: 'sparql'},
{name: 'SQL', mime: 'text/x-sql', mode: 'sql'},
{name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'},
Expand Down
5 changes: 2 additions & 3 deletions mode/mirc/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,9 @@ <h2>mIRC mode</h2>
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
tabMode: "indent",
theme: "twilight",
theme: "twilight",
lineNumbers: true,
matchBrackets: true,
matchBrackets: true,
indentUnit: 4,
mode: "text/mirc"
});
Expand Down
20 changes: 4 additions & 16 deletions mode/octave/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,16 @@ <h2>Octave mode</h2>

<div><textarea id="code" name="code">
%numbers
1234
1234i
1234j
.234
.234j
2.23i
23e2
12E1j
123D-4
0x234
[1234 1234i 1234j]
[.234 .234j 2.23i]
[23e2 12E1j 123D-4 0x234]

%strings
'asda''a'
"asda""a"

%identifiers
a
as123
__asd__
a + as123 - __asd__

%operators
-
Expand Down Expand Up @@ -73,10 +64,8 @@ <h2>Octave mode</h2>
global persistent

%one line comment
...one line comment
%{ multi
line commment %}
1

</textarea></div>
<script>
Expand All @@ -86,7 +75,6 @@ <h2>Octave mode</h2>
singleLineStringErrors: false},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift",
matchBrackets: true
});
</script>
Expand Down
10 changes: 6 additions & 4 deletions mode/octave/octave.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@ CodeMirror.defineMode("octave", function() {

var builtins = wordRegexp([
'error', 'eval', 'function', 'abs', 'acos', 'atan', 'asin', 'cos',
'cosh', 'exp', 'log', 'prod', 'log10', 'max', 'min', 'sign', 'sin', 'sinh',
'cosh', 'exp', 'log', 'prod', 'sum', 'log10', 'max', 'min', 'sign', 'sin', 'sinh',
'sqrt', 'tan', 'reshape', 'break', 'zeros', 'default', 'margin', 'round', 'ones',
'rand', 'syn', 'ceil', 'floor', 'size', 'clear', 'zeros', 'eye', 'mean', 'std', 'cov',
'det', 'eig', 'inv', 'norm', 'rank', 'trace', 'expm', 'logm', 'sqrtm', 'linspace', 'plot',
'title', 'xlabel', 'ylabel', 'legend', 'text', 'meshgrid', 'mesh', 'num2str'
'title', 'xlabel', 'ylabel', 'legend', 'text', 'grid', 'meshgrid', 'mesh', 'num2str',
'fft', 'ifft', 'arrayfun', 'cellfun', 'input', 'fliplr', 'flipud', 'ismember'
]);

var keywords = wordRegexp([
'return', 'case', 'switch', 'else', 'elseif', 'end', 'endif', 'endfunction',
'if', 'otherwise', 'do', 'for', 'while', 'try', 'catch', 'classdef', 'properties', 'events',
'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'disp', 'until', 'continue'
'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'sprintf', 'disp', 'until',
'continue', 'pkg'
]);


Expand Down Expand Up @@ -59,7 +61,7 @@ CodeMirror.defineMode("octave", function() {
return 'comment';
}

if (stream.match(/^(%)|(\.\.\.)/)){
if (stream.match(/^[%#]/)){
stream.skipToEnd();
return 'comment';
}
Expand Down
4 changes: 1 addition & 3 deletions mode/php/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ <h2>PHP mode</h2>
matchBrackets: true,
mode: "application/x-httpd-php",
indentUnit: 4,
indentWithTabs: true,
enterMode: "keep",
tabMode: "shift"
indentWithTabs: true
});
</script>

Expand Down
121 changes: 121 additions & 0 deletions mode/puppet/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<!doctype html>

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

<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="puppet.js"></script>
<style>
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
.cm-s-default span.cm-arrow { color: red; }
</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>

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

<article>
<h2>Puppet mode</h2>
<form><textarea id="code" name="code">
# == Class: automysqlbackup
#
# Puppet module to install AutoMySQLBackup for periodic MySQL backups.
#
# class { 'automysqlbackup':
# backup_dir => '/mnt/backups',
# }
#

class automysqlbackup (
$bin_dir = $automysqlbackup::params::bin_dir,
$etc_dir = $automysqlbackup::params::etc_dir,
$backup_dir = $automysqlbackup::params::backup_dir,
$install_multicore = undef,
$config = {},
$config_defaults = {},
) inherits automysqlbackup::params {

# Ensure valid paths are assigned
validate_absolute_path($bin_dir)
validate_absolute_path($etc_dir)
validate_absolute_path($backup_dir)

# Create a subdirectory in /etc for config files
file { $etc_dir:
ensure => directory,
owner => 'root',
group => 'root',
mode => '0750',
}

# Create an example backup file, useful for reference
file { "${etc_dir}/automysqlbackup.conf.example":
ensure => file,
owner => 'root',
group => 'root',
mode => '0660',
source => 'puppet:///modules/automysqlbackup/automysqlbackup.conf',
}

# Add files from the developer
file { "${etc_dir}/AMB_README":
ensure => file,
source => 'puppet:///modules/automysqlbackup/AMB_README',
}
file { "${etc_dir}/AMB_LICENSE":
ensure => file,
source => 'puppet:///modules/automysqlbackup/AMB_LICENSE',
}

# Install the actual binary file
file { "${bin_dir}/automysqlbackup":
ensure => file,
owner => 'root',
group => 'root',
mode => '0755',
source => 'puppet:///modules/automysqlbackup/automysqlbackup',
}

# Create the base backup directory
file { $backup_dir:
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
}

# If you'd like to keep your config in hiera and pass it to this class
if !empty($config) {
create_resources('automysqlbackup::backup', $config, $config_defaults)
}

# If using RedHat family, must have the RPMforge repo's enabled
if $install_multicore {
package { ['pigz', 'pbzip2']: ensure => installed }
}

}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: "text/x-puppet",
matchBrackets: true,
indentUnit: 4
});
</script>

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

</article>
204 changes: 204 additions & 0 deletions mode/puppet/puppet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
CodeMirror.defineMode("puppet", function () {
// Stores the words from the define method
var words = {};
// Taken, mostly, from the Puppet official variable standards regex
var variable_regex = /({)?([a-z][a-z0-9_]*)?((::[a-z][a-z0-9_]*)*::)?[a-zA-Z0-9_]+(})?/;

// Takes a string of words separated by spaces and adds them as
// keys with the value of the first argument 'style'
function define(style, string) {
var split = string.split(' ');
for (var i = 0; i < split.length; i++) {
words[split[i]] = style;
}
}

// Takes commonly known puppet types/words and classifies them to a style
define('keyword', 'class define site node include import inherits');
define('keyword', 'case if else in and elsif default or');
define('atom', 'false true running present absent file directory undef');
define('builtin', 'action augeas burst chain computer cron destination dport exec ' +
'file filebucket group host icmp iniface interface jump k5login limit log_level ' +
'log_prefix macauthorization mailalias maillist mcx mount nagios_command ' +
'nagios_contact nagios_contactgroup nagios_host nagios_hostdependency ' +
'nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service ' +
'nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo ' +
'nagios_servicegroup nagios_timeperiod name notify outiface package proto reject ' +
'resources router schedule scheduled_task selboolean selmodule service source ' +
'sport ssh_authorized_key sshkey stage state table tidy todest toports tosource ' +
'user vlan yumrepo zfs zone zpool');

// After finding a start of a string ('|") this function attempts to find the end;
// If a variable is encountered along the way, we display it differently when it
// is encapsulated in a double-quoted string.
function tokenString(stream, state) {
var current, prev, found_var = false;
while (!stream.eol() && (current = stream.next()) != state.pending) {
if (current === '$' && prev != '\\' && state.pending == '"') {
found_var = true;
break;
}
prev = current;
}
if (found_var) {
stream.backUp(1);
}
if (current == state.pending) {
state.continueString = false;
} else {
state.continueString = true;
}
return "string";
}

// Main function
function tokenize(stream, state) {
// Matches one whole word
var word = stream.match(/[\w]+/, false);
// Matches attributes (i.e. ensure => present ; 'ensure' would be matched)
var attribute = stream.match(/(\s+)?\w+\s+=>.*/, false);
// Matches non-builtin resource declarations
// (i.e. "apache::vhost {" or "mycustomclasss {" would be matched)
var resource = stream.match(/(\s+)?[\w:_]+(\s+)?{/, false);
// Matches virtual and exported resources (i.e. @@user { ; and the like)
var special_resource = stream.match(/(\s+)?[@]{1,2}[\w:_]+(\s+)?{/, false);

// Finally advance the stream
var ch = stream.next();

// Have we found a variable?
if (ch === '$') {
if (stream.match(variable_regex)) {
// If so, and its in a string, assign it a different color
return state.continueString ? 'variable-2' : 'variable';
}
// Otherwise return an invalid variable
return "error";
}
// Should we still be looking for the end of a string?
if (state.continueString) {
// If so, go through the loop again
stream.backUp(1);
return tokenString(stream, state);
}
// Are we in a definition (class, node, define)?
if (state.inDefinition) {
// If so, return def (i.e. for 'class myclass {' ; 'myclass' would be matched)
if (stream.match(/(\s+)?[\w:_]+(\s+)?/)) {
return 'def';
}
// Match the rest it the next time around
stream.match(/\s+{/);
state.inDefinition = false;
}
// Are we in an 'include' statement?
if (state.inInclude) {
// Match and return the included class
stream.match(/(\s+)?\S+(\s+)?/);
state.inInclude = false;
return 'def';
}
// Do we just have a function on our hands?
// In 'ensure_resource("myclass")', 'ensure_resource' is matched
if (stream.match(/(\s+)?\w+\(/)) {
stream.backUp(1);
return 'def';
}
// Have we matched the prior attribute regex?
if (attribute) {
stream.match(/(\s+)?\w+/);
return 'tag';
}
// Do we have Puppet specific words?
if (word && words.hasOwnProperty(word)) {
// Negates the initial next()
stream.backUp(1);
// Acutally move the stream
stream.match(/[\w]+/);
// We want to process these words differently
// do to the importance they have in Puppet
if (stream.match(/\s+\S+\s+{/, false)) {
state.inDefinition = true;
}
if (word == 'include') {
state.inInclude = true;
}
// Returns their value as state in the prior define methods
return words[word];
}
// Is there a match on a reference?
if (/(\s+)?[A-Z]/.test(word)) {
// Negate the next()
stream.backUp(1);
// Match the full reference
stream.match(/(\s+)?[A-Z][\w:_]+/);
return 'def';
}
// Have we matched the prior resource regex?
if (resource) {
stream.match(/(\s+)?[\w:_]+/);
return 'def';
}
// Have we matched the prior special_resource regex?
if (special_resource) {
stream.match(/(\s+)?[@]{1,2}/);
return 'special';
}
// Match all the comments. All of them.
if (ch == "#") {
stream.skipToEnd();
return "comment";
}
// Have we found a string?
if (ch == "'" || ch == '"') {
// Store the type (single or double)
state.pending = ch;
// Perform the looping function to find the end
return tokenString(stream, state);
}
// Match all the brackets
if (ch == '{' || ch == '}') {
return 'bracket';
}
// Match characters that we are going to assume
// are trying to be regex
if (ch == '/') {
stream.match(/.*\//);
return 'variable-3';
}
// Match all the numbers
if (ch.match(/[0-9]/)) {
stream.eatWhile(/[0-9]+/);
return 'number';
}
// Match the '=' and '=>' operators
if (ch == '=') {
if (stream.peek() == '>') {
stream.next();
}
return "operator";
}
// Keep advancing through all the rest
stream.eatWhile(/[\w-]/);
// Return a blank line for everything else
return null;
}
// Start it all
return {
startState: function () {
var state = {};
state.inDefinition = false;
state.inInclude = false;
state.continueString = false;
state.pending = false;
return state;
},
token: function (stream, state) {
// Strip the spaces, but regex will account for them eitherway
if (stream.eatSpace()) return null;
// Go through the main process
return tokenize(stream, state);
}
};
});
CodeMirror.defineMIME("text/x-puppet", "puppet");
2 changes: 0 additions & 2 deletions mode/python/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ <h2>Cython mode</h2>
singleLineStringErrors: false},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift",
matchBrackets: true
});

Expand All @@ -160,7 +159,6 @@ <h2>Cython mode</h2>
singleLineStringErrors: false},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift",
matchBrackets: true
});
</script>
Expand Down
4 changes: 4 additions & 0 deletions mode/python/python.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
return 'builtin';
}

if (stream.match(/^(self|cls)\b/)) {
return "variable-2";
}

if (stream.match(identifiers)) {
if (state.lastToken == 'def' || state.lastToken == 'class') {
return 'def';
Expand Down
3 changes: 1 addition & 2 deletions mode/rpm/changes/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ <h2>RPM changes mode</h2>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "changes"},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift"
indentUnit: 4
});
</script>

Expand Down
1 change: 1 addition & 0 deletions mode/rst/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/mode/overlay.js"></script>
<script src="rst.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
Expand Down
Loading