74 changes: 51 additions & 23 deletions doc/manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
<section class=first id=overview>
<h2 style="position: relative">
User manual and reference guide
<span style="color: #888; font-size: 1rem; position: absolute; right: 0; bottom: 0">version 4.7.0</span>
<span style="color: #888; font-size: 1rem; position: absolute; right: 0; bottom: 0">version 4.8.0</span>
</h2>

<p>CodeMirror is a code-editor component that can be embedded in
Expand Down Expand Up @@ -576,6 +576,13 @@ <h2>Events</h2>
<dt id="event_scroll"><code><strong>"scroll"</strong> (instance: CodeMirror)</code></dt>
<dd>Fires when the editor is scrolled.</dd>

<dt id="event_scrollCursorIntoView"><code><strong>"scrollCursorIntoView"</strong> (instance: CodeMirror, event: Event)</code></dt>
<dd>Fires when the editor tries to scroll its cursor into view.
Can be hooked into to take care of additional scrollable
containers around the editor. When the event object has
its <code>preventDefault</code> method called, CodeMirror will
not itself try to scroll the window.</dd>

<dt id="event_update"><code><strong>"update"</strong> (instance: CodeMirror)</code></dt>
<dd>Will be fired whenever CodeMirror updates its DOM display.</dd>

Expand Down Expand Up @@ -702,26 +709,36 @@ <h2>Key Maps</h2>
names defined here are <code>Enter</code>, <code>F5</code>,
and <code>Q</code>. These can be prefixed
with <code>Shift-</code>, <code>Cmd-</code>, <code>Ctrl-</code>,
and <code>Alt-</code> (in that order!) to specify a modifier. So
for example, <code>Shift-Ctrl-Space</code> would be a valid key
and <code>Alt-</code> to specify a modifier. So for
example, <code>Shift-Ctrl-Space</code> would be a valid key
identifier.</p>

<p>Common example: map the Tab key to insert spaces instead of a tab
character.</p>

<pre data-lang="javascript">
{
editor.setOption("extraKeys", {
Tab: function(cm) {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
cm.replaceSelection(spaces);
}
}</pre>
});</pre>

<p>Alternatively, a character can be specified directly by
surrounding it in single quotes, for example <code>'$'</code>
or <code>'q'</code>. Due to limitations in the way browsers fire
key events, these may not be prefixed with modifiers.</p>

<p id="normalizeKeyMap">Multi-stroke key bindings can be specified
by separating the key names by spaces in the property name, for
example <code>Ctrl-X Ctrl-V</code>. When a map contains
multi-stoke bindings or keys with modifiers that are not specified
in the default order (<code>Shift-Cmd-Ctrl-Alt</code>), you must
call <code>CodeMirror.normalizeKeyMap</code> on it before it can
be used. This function takes a keymap and modifies it to normalize
modifier order and properly recognize multi-stroke bindings. It
will return the keymap itself.</p>

<p>The <code>CodeMirror.keyMap</code> object associates key maps
with names. User code and key map definitions can assign extra
properties to this object. Anywhere where a key map is expected, a
Expand All @@ -740,7 +757,8 @@ <h2>Key Maps</h2>
behavior) should be given a turn.</p>

<p>Keys mapped to command names that start with the
characters <code>"go"</code> (which should be used for
characters <code>"go"</code> or to functions that have a
truthy <code>motion</code> property (which should be used for
cursor-movement actions) will be fired even when an
extra <code>Shift</code> modifier is present (i.e. <code>"Up":
"goLineUp"</code> matches both up and shift-up). This is used to
Expand All @@ -752,14 +770,15 @@ <h2>Key Maps</h2>
be searched. It can hold either a single key map or an array of
key maps.</p>

<p>When a key map contains a <code>nofallthrough</code> property
set to <code>true</code>, keys matched against that map will be
ignored if they don't match any of the bindings in the map (no
further child maps will be tried). When
the <code>disableInput</code> property is set
to <code>true</code>, the default effect of inserting a character
will be suppressed when the key map is active as the top-level
map.</p>
<p>When a key map needs to set something up when it becomes
active, or tear something down when deactivated, it can
contain <code>attach</code> and/or <code>detach</code> properties,
which should hold functions that take the editor instance and the
next or previous keymap. Note that this only works for the
<a href="#option_keyMap">top-level keymap</a>, not for fallthrough
maps or maps added
with <a href="#option_extraKeys"><code>extraKeys</code></a>
or <a href="#addKeyMap"><code>addKeyMap</code></a>.</p>
</section>

<section id=commands>
Expand Down Expand Up @@ -1620,10 +1639,11 @@ <h3 id="api_decoration">Widget, gutter, and decoration methods</h3>
to which element this class should be applied, can can be one
of <code>"text"</code> (the text element, which lies in front of
the selection), <code>"background"</code> (a background element
that will be behind the selection), or <code>"wrap"</code> (the
wrapper node that wraps all of the line's elements, including
gutter elements). <code>class</code> should be the name of the
class to apply.</dd>
that will be behind the selection), <code>"gutter"</code> (the
line's gutter space), or <code>"wrap"</code> (the wrapper node
that wraps all of the line's elements, including gutter
elements). <code>class</code> should be the name of the class to
apply.</dd>

<dt id="removeLineClass"><code><strong>doc.removeLineClass</strong>(line: integer|LineHandle, where: string, class: string) → LineHandle</code></dt>
<dd>Remove a CSS class from a line. <code>line</code> can be a
Expand Down Expand Up @@ -1830,6 +1850,13 @@ <h3 id="api_mode">Mode, state, and token-related methods</h3>
edits were recently made and highlighting has not yet completed.
</dd>

<dt id="getLineTokens"><code><strong>cm.getLineTokens</strong>(line: integer, ?precise: boolean) → array&lt;{start, end, string, type, state}&gt;</code></dt>
<dd>This is similar
to <a href="#getTokenAt"><code>getTokenAt</code></a>, but
collects all tokens for a given line into an array. It is much
cheaper than repeatedly calling <code>getTokenAt</code>, which
re-parses the part of the line before the token for every call.</dd>

<dt id="getTokenTypeAt"><code><strong>cm.getTokenTypeAt</strong>(pos: {line, ch}) → string</code></dt>
<dd>This is a (much) cheaper version
of <a href="#getTokenAt"><code>getTokenAt</code></a> useful for
Expand Down Expand Up @@ -2600,11 +2627,12 @@ <h2 id="addons">Addons</h2>
properties <code>mimes</code>, which holds an array of MIME
types for modes with multiple MIMEs associated,
and <code>ext</code>, which holds an array of file extensions
associated with this mode. Two convenience
functions, <code>CodeMirror.findModeByMIME</code>
and <code>CodeMirror.findModeByExtension</code> are provided,
which return such an object given a MIME or extension string.
Note that, for historical reasons, this file resides in the
associated with this mode. Three convenience
functions, <code>CodeMirror.findModeByMIME</code>,
and <code>CodeMirror.findModeByExtension</code>,
and <code>CodeMirror.findModeByName</code> are provided, which
return such an object given a MIME or extension string. Note
that, for historical reasons, this file resides in the
top-level <code>mode</code> directory, not
under <code>addon</code>. <a href="../demo/loadmode.html">Demo</a>.</dd>

Expand Down
4 changes: 4 additions & 0 deletions doc/realworld.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="http://paperjs.org/">Paper.js</a> (graphics scripting)</li>
<li><a href="http://prinbit.com/">PrinBit</a> (collaborative coding tool)</li>
<li><a href="http://prose.io/">Prose.io</a> (github content editor)</li>
<li><a href="https://pypi.python.org/pypi/PubliForge/">PubliForge</a> (online publishing system)</li>
<li><a href="http://www.puzzlescript.net/">Puzzlescript</a> (puzzle game engine)</li>
<li><a href="http://ql.io/">ql.io</a> (http API query helper)</li>
<li><a href="http://qyapp.com">QiYun web app platform</a></li>
Expand All @@ -133,9 +134,11 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="https://www.shadertoy.com/">Shadertoy</a> (shader sharing)</li>
<li><a href="http://www.sketchpatch.net/labs/livecodelabIntro.html">sketchPatch Livecodelab</a></li>
<li><a href="http://www.skulpt.org/">Skulpt</a> (in-browser Python environment)</li>
<li><a href="http://snaptomato.appspot.com/editor.html">Snap Tomato</a> (HTML editing/testing page)</li>
<li><a href="http://snippets.pro/">Snippets.pro</a> (code snippet sharing)</li>
<li><a href="http://www.solidshops.com/">SolidShops</a> (hosted e-commerce platform)</li>
<li><a href="http://sqlfiddle.com">SQLFiddle</a> (SQL playground)</li>
<li><a href="http://xuanji.appspot.com/isicp/">Structure and Interpretation of Computer Programs</a>, Interactive Version</li>
<li><a href="http://syframework.alwaysdata.net">SyBox</a> (PHP playground)</li>
<li><a href="http://www.tagspaces.org/">TagSpaces</a> (personal data manager)</li>
<li><a href="https://thefiletree.com">The File Tree</a> (collab editor)</li>
Expand All @@ -153,6 +156,7 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="http://webglplayground.net/">WebGL playground</a></li>
<li><a href="https://www.webkit.org/blog/2518/state-of-web-inspector/#source-code">WebKit Web inspector</a></li>
<li><a href="http://www.wescheme.org/">WeScheme</a> (learning tool)</li>
<li><a href="https://github.com/b3log/wide">Wide</a> (golang web IDE)</li>
<li><a href="http://wordpress.org/extend/plugins/codemirror-for-codeeditor/">WordPress plugin</a></li>
<li><a href="https://www.writelatex.com">writeLaTeX</a> (Collaborative LaTeX Editor)</li>
<li><a href="http://www.xosystem.org/home/applications_websites/xosystem_website/xoside_EN.php">XOSide</a> (online editor)</li>
Expand Down
12 changes: 12 additions & 0 deletions doc/releases.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ <h2>Release notes and version history</h2>

<h2>Version 4.x</h2>

<p class="rel">22-11-2014: <a href="http://codemirror.net/codemirror-4.8.zip">Version 4.8</a>:</p>

<ul class="rel-note">
<li>Built-in support for <a href="manual.html#normalizeKeyMap">multi-stroke key bindings</a>.</li>
<li>New method: <a href="manual.html#getLineTokens"><code>getLineTokens</code></a>.</li>
<li>New modes: <a href="../mode/dockerfile/index.html">dockerfile</a>, <a href="../mode/idl/index.html">IDL</a>, <a href="../mode/clike/index.html">Objective C</a> (crude).</li>
<li>Support styling of gutter backgrounds, allow <code>"gutter"</code> styles in <a href="manual.html#addLineClass"><code>addLineClass</code></a>.</li>
<li>Many improvements to the <a href="../demo/vim.html">Vim mode</a>, rewritten visual mode.</li>
<li>Improvements to modes: <a href="../mode/gfm/index.html">gfm</a> (strikethrough), <a href="../mode/sparql/index.html">SPARQL</a> (version 1.1 support), and <a href="../mode/stex/index.html">sTeX</a> (no more runaway math mode).
<li>Full <a href="https://github.com/codemirror/CodeMirror/compare/4.7.0...4.8.0">list of patches</a>.</li>
</ul>

<p class="rel">20-10-2014: <a href="http://codemirror.net/codemirror-4.7.zip">Version 4.7</a>:</p>

<ul class="rel-note">
Expand Down
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ <h2>This is CodeMirror</h2>
<script src="lib/codemirror.js"></script>
<script>
var editor = CodeMirror.fromTextArea(myTextarea, {
mode: "text/html"
lineNumbers: true
});
</script></textarea>
<select id="demolist" onchange="document.location = this.options[this.selectedIndex].value;">
Expand Down Expand Up @@ -85,7 +85,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 4.7</strong> (<a href="doc/releases.html">Release notes</a>)</div>
<div><strong>version 4.8</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 @@ -165,7 +165,7 @@ <h2>Community</h2>
license that CodeMirror uses.</p>

<p>Discussion around the project is done on
a <a href="http://groups.google.com/group/codemirror">mailing list</a>.
a <a href="http://discuss.codemirror.net">discussion forum</a>.
There is also
the <a href="http://groups.google.com/group/codemirror-announce">codemirror-announce</a>
list, which is only used for major announcements (such as new
Expand Down
47 changes: 19 additions & 28 deletions keymap/emacs.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@

// Actual keymap

var keyMap = CodeMirror.keyMap.emacs = {
var keyMap = CodeMirror.keyMap.emacs = CodeMirror.normalizeKeyMap({
"Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"));},
"Ctrl-K": repeated(function(cm) {
var start = cm.getCursor(), end = cm.clipPos(Pos(start.line));
Expand Down Expand Up @@ -353,27 +353,7 @@
"Alt-/": "autocomplete",
"Ctrl-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto",

"Alt-G": function(cm) {cm.setOption("keyMap", "emacs-Alt-G");},
"Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");},
"Ctrl-Q": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-Q");},
"Ctrl-U": addPrefixMap
};

CodeMirror.keyMap["emacs-Ctrl-X"] = {
"Tab": function(cm) {
cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit"));
},
"Ctrl-X": function(cm) {
cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor"));
},

"Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": repeated("undo"), "K": "close",
"Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), true); },
auto: "emacs", nofallthrough: true, disableInput: true
};

CodeMirror.keyMap["emacs-Alt-G"] = {
"G": function(cm) {
"Alt-G G": function(cm) {
var prefix = getPrefix(cm, true);
if (prefix != null && prefix > 0) return cm.setCursor(prefix - 1);

Expand All @@ -383,13 +363,24 @@
cm.setCursor(num - 1);
});
},
auto: "emacs", nofallthrough: true, disableInput: true
};

CodeMirror.keyMap["emacs-Ctrl-Q"] = {
"Tab": repeated("insertTab"),
auto: "emacs", nofallthrough: true
};
"Ctrl-X Tab": function(cm) {
cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit"));
},
"Ctrl-X Ctrl-X": function(cm) {
cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor"));
},
"Ctrl-X Ctrl-S": "save",
"Ctrl-X Ctrl-W": "save",
"Ctrl-X S": "saveAll",
"Ctrl-X F": "open",
"Ctrl-X U": repeated("undo"),
"Ctrl-X K": "close",
"Ctrl-X Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), true); },

"Ctrl-Q Tab": repeated("insertTab"),
"Ctrl-U": addPrefixMap
});

var prefixMap = {"Ctrl-G": clearPrefix};
function regPrefix(d) {
Expand Down
29 changes: 14 additions & 15 deletions keymap/sublime.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,7 @@

map["Alt-Q"] = "wrapLines";

var mapK = CodeMirror.keyMap["sublime-Ctrl-K"] = {auto: "sublime", nofallthrough: true};

map[ctrl + "K"] = function(cm) {cm.setOption("keyMap", "sublime-Ctrl-K");};
var cK = ctrl + "K ";

function modifyWordOrSelection(cm, mod) {
cm.operation(function() {
Expand All @@ -409,9 +407,9 @@
});
}

mapK[ctrl + "Backspace"] = "delLineLeft";
map[cK + ctrl + "Backspace"] = "delLineLeft";

cmds[mapK[ctrl + "K"] = "delLineRight"] = function(cm) {
cmds[map[cK + ctrl + "K"] = "delLineRight"] = function(cm) {
cm.operation(function() {
var ranges = cm.listSelections();
for (var i = ranges.length - 1; i >= 0; i--)
Expand All @@ -420,22 +418,22 @@
});
};

cmds[mapK[ctrl + "U"] = "upcaseAtCursor"] = function(cm) {
cmds[map[cK + ctrl + "U"] = "upcaseAtCursor"] = function(cm) {
modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); });
};
cmds[mapK[ctrl + "L"] = "downcaseAtCursor"] = function(cm) {
cmds[map[cK + ctrl + "L"] = "downcaseAtCursor"] = function(cm) {
modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); });
};

cmds[mapK[ctrl + "Space"] = "setSublimeMark"] = function(cm) {
cmds[map[cK + ctrl + "Space"] = "setSublimeMark"] = function(cm) {
if (cm.state.sublimeMark) cm.state.sublimeMark.clear();
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
};
cmds[mapK[ctrl + "A"] = "selectToSublimeMark"] = function(cm) {
cmds[map[cK + ctrl + "A"] = "selectToSublimeMark"] = function(cm) {
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
if (found) cm.setSelection(cm.getCursor(), found);
};
cmds[mapK[ctrl + "W"] = "deleteToSublimeMark"] = function(cm) {
cmds[map[cK + ctrl + "W"] = "deleteToSublimeMark"] = function(cm) {
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
if (found) {
var from = cm.getCursor(), to = found;
Expand All @@ -444,21 +442,21 @@
cm.replaceRange("", from, to);
}
};
cmds[mapK[ctrl + "X"] = "swapWithSublimeMark"] = function(cm) {
cmds[map[cK + ctrl + "X"] = "swapWithSublimeMark"] = function(cm) {
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
if (found) {
cm.state.sublimeMark.clear();
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
cm.setCursor(found);
}
};
cmds[mapK[ctrl + "Y"] = "sublimeYank"] = function(cm) {
cmds[map[cK + ctrl + "Y"] = "sublimeYank"] = function(cm) {
if (cm.state.sublimeKilled != null)
cm.replaceSelection(cm.state.sublimeKilled, null, "paste");
};

mapK[ctrl + "G"] = "clearBookmarks";
cmds[mapK[ctrl + "C"] = "showInCenter"] = function(cm) {
map[cK + ctrl + "G"] = "clearBookmarks";
cmds[map[cK + ctrl + "C"] = "showInCenter"] = function(cm) {
var pos = cm.cursorCoords(null, "local");
cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2);
};
Expand Down Expand Up @@ -530,12 +528,13 @@

map["Shift-" + ctrl + "["] = "fold";
map["Shift-" + ctrl + "]"] = "unfold";
mapK[ctrl + "0"] = mapK[ctrl + "j"] = "unfoldAll";
map[cK + ctrl + "0"] = map[cK + ctrl + "j"] = "unfoldAll";

map[ctrl + "I"] = "findIncremental";
map["Shift-" + ctrl + "I"] = "findIncrementalReverse";
map[ctrl + "H"] = "replace";
map["F3"] = "findNext";
map["Shift-F3"] = "findPrev";

CodeMirror.normalizeKeyMap(map);
});
1,446 changes: 694 additions & 752 deletions keymap/vim.js

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions lib/codemirror.css
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursors {
.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}

Expand Down Expand Up @@ -125,6 +125,7 @@ div.CodeMirror-overwrite div.CodeMirror-cursor {}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-strikethrough {text-decoration: line-through;}

.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
Expand Down Expand Up @@ -209,6 +210,11 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
height: 100%;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
Expand Down Expand Up @@ -305,5 +311,8 @@ div.CodeMirror-cursors {
}
}

/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }

/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }
366 changes: 229 additions & 137 deletions lib/codemirror.js

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions mode/clike/clike.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,4 +471,19 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
modeProps: {fold: ["brace", "include"]}
});

def("text/x-objectivec", {
name: "clike",
keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginery BOOL Class bycopy byref id IMP in " +
"inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),
atoms: words("YES NO NULL NILL ON OFF"),
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$]/);
return "keyword";
},
"#": cppHook
},
modeProps: {fold: "brace"}
});

});
26 changes: 26 additions & 0 deletions mode/clike/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,26 @@ <h2>C++ example</h2>
}
</textarea></div>

<h2>Objective-C example</h2>

<div><textarea id="objectivec-code">
/*
This is a longer comment
That spans two lines
*/

#import <Test/Test.h>
@implementation YourAppDelegate

// This is a one-line comment

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
char myString[] = "This is a C character array";
int test = 5;
return YES;
}
</textarea></div>

<h2>Java example</h2>

<div><textarea id="java-code">
Expand Down Expand Up @@ -202,6 +222,11 @@ <h2>Scala example</h2>
matchBrackets: true,
mode: "text/x-java"
});
var objectivecEditor = CodeMirror.fromTextArea(document.getElementById("objectivec-code"), {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-objectivec"
});
var scalaEditor = CodeMirror.fromTextArea(document.getElementById("scala-code"), {
lineNumbers: true,
matchBrackets: true,
Expand All @@ -220,6 +245,7 @@ <h2>Scala example</h2>
<p><strong>MIME types defined:</strong> <code>text/x-csrc</code>
(C), <code>text/x-c++src</code> (C++), <code>text/x-java</code>
(Java), <code>text/x-csharp</code> (C#),
<code>text/x-objectivec</code> (Objective-C),
<code>text/x-scala</code> (Scala), <code>text/x-vertex</code>
and <code>x-shader/x-fragment</code> (shader programs).</p>
</article>
2 changes: 1 addition & 1 deletion mode/css/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
override = "string-2";
return "maybeprop";
} else if (allowNested) {
override = stream.match(/^\s*:/, false) ? "property" : "tag";
override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
return "block";
} else {
override += " error";
Expand Down
80 changes: 80 additions & 0 deletions mode/dockerfile/dockerfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

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

// Collect all Dockerfile directives
var instructions = ["from", "maintainer", "run", "cmd", "expose", "env",
"add", "copy", "entrypoint", "volume", "user",
"workdir", "onbuild"],
instructionRegex = "(" + instructions.join('|') + ")",
instructionOnlyLine = new RegExp(instructionRegex + "\\s*$", "i"),
instructionWithArguments = new RegExp(instructionRegex + "(\\s+)", "i");

CodeMirror.defineSimpleMode("dockerfile", {
start: [
// Block comment: This is a line starting with a comment
{
regex: /#.*$/,
token: "comment",
next: "start"
},
// Highlight an instruction without any arguments (for convenience)
{
regex: instructionOnlyLine,
token: "variable-2",
next: "start"
},
// Highlight an instruction followed by arguments
{
regex: instructionWithArguments,
token: ["variable-2", null],
next: "arguments"
},
// Fail-safe return to start
{
token: null,
next: "start"
}
],
arguments: [
{
// Line comment without instruction arguments is an error
regex: /#.*$/,
token: "error",
next: "start"
},
{
regex: /[^#]+\\$/,
token: null,
next: "arguments"
},
{
// Match everything except for the inline comment
regex: /[^#]+/,
token: null,
next: "start"
},
{
regex: /$/,
token: null,
next: "start"
},
// Fail safe return to start
{
token: null,
next: "start"
}
]
});

CodeMirror.defineMIME("text/x-dockerfile", "dockerfile");
});
72 changes: 72 additions & 0 deletions mode/dockerfile/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!doctype html>

<title>CodeMirror: Dockerfile 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/mode/simple.js"></script>
<script src="dockerfile.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"><h1>CodeMirror</h1><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/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">Dockerfile</a>
</ul>
</div>

<article>
<h2>Dockerfile mode</h2>
<form><textarea id="code" name="code"># Install Ghost blogging platform and run development environment
#
# VERSION 1.0.0

FROM ubuntu:12.10
MAINTAINER Amer Grgic "amer@livebyt.es"
WORKDIR /data/ghost

# Install dependencies for nginx installation
RUN apt-get update
RUN apt-get install -y python g++ make software-properties-common --force-yes
RUN add-apt-repository ppa:chris-lea/node.js
RUN apt-get update
# Install unzip
RUN apt-get install -y unzip
# Install curl
RUN apt-get install -y curl
# Install nodejs & npm
RUN apt-get install -y rlwrap
RUN apt-get install -y nodejs
# Download Ghost v0.4.1
RUN curl -L https://ghost.org/zip/ghost-latest.zip -o /tmp/ghost.zip
# Unzip Ghost zip to /data/ghost
RUN unzip -uo /tmp/ghost.zip -d /data/ghost
# Add custom config js to /data/ghost
ADD ./config.example.js /data/ghost/config.js
# Install Ghost with NPM
RUN cd /data/ghost/ && npm install --production
# Expose port 2368
EXPOSE 2368
# Run Ghost
CMD ["npm","start"]
</textarea></form>

<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
mode: "dockerfile"
});
</script>

<p>Dockerfile syntac highlighting for CodeMirror.</p>

<p><strong>MIME types defined:</strong> <code>text/x-dockerfile</code></p>
</article>
3 changes: 2 additions & 1 deletion mode/gfm/gfm.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ CodeMirror.defineMode("gfm", function(config, modeConfig) {
var markdownConfig = {
underscoresBreakWords: false,
taskLists: true,
fencedCodeBlocks: true
fencedCodeBlocks: true,
strikethrough: true
};
for (var attr in modeConfig) {
markdownConfig[attr] = modeConfig[attr];
Expand Down
11 changes: 11 additions & 0 deletions mode/gfm/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<script src="../css/css.js"></script>
<script src="../htmlmixed/htmlmixed.js"></script>
<script src="../clike/clike.js"></script>
<script src="../meta.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"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
Expand Down Expand Up @@ -41,6 +42,16 @@ <h2>GFM mode</h2>

Underscores_are_allowed_between_words.

## Strikethrough text

GFM adds syntax to strikethrough text, which is missing from standard Markdown.

~~Mistaken text.~~
~~**works with other fomatting**~~

~~spans across
lines~~

## Fenced code blocks (and syntax highlighting)

```javascript
Expand Down
49 changes: 49 additions & 0 deletions mode/gfm/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
"[variable-2&formatting&formatting-list&formatting-list-ul - ][meta&formatting&formatting-task [ ]]][variable-2 foo]",
"[variable-2&formatting&formatting-list&formatting-list-ul - ][property&formatting&formatting-task [x]]][variable-2 foo]");

FT("formatting_strikethrough",
"[strikethrough&formatting&formatting-strikethrough ~~][strikethrough foo][strikethrough&formatting&formatting-strikethrough ~~]");

FT("formatting_strikethrough",
"foo [strikethrough&formatting&formatting-strikethrough ~~][strikethrough bar][strikethrough&formatting&formatting-strikethrough ~~]");

MT("emInWordAsterisk",
"foo[em *bar*]hello");

Expand Down Expand Up @@ -161,4 +167,47 @@
"Commit: [link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2]",
"Issue: [link #1]",
"Link: [link http://www.example.com/]");

MT("strikethrough",
"[strikethrough ~~foo~~]");

MT("strikethroughWithStartingSpace",
"~~ foo~~");

MT("strikethroughUnclosedStrayTildes",
"[strikethrough ~~foo~~~]");

MT("strikethroughUnclosedStrayTildes",
"[strikethrough ~~foo ~~]");

MT("strikethroughUnclosedStrayTildes",
"[strikethrough ~~foo ~~ bar]");

MT("strikethroughUnclosedStrayTildes",
"[strikethrough ~~foo ~~ bar~~]hello");

MT("strikethroughOneLetter",
"[strikethrough ~~a~~]");

MT("strikethroughWrapped",
"[strikethrough ~~foo]",
"[strikethrough foo~~]");

MT("strikethroughParagraph",
"[strikethrough ~~foo]",
"",
"foo[strikethrough ~~bar]");

MT("strikethroughEm",
"[strikethrough ~~foo][em&strikethrough *bar*][strikethrough ~~]");

MT("strikethroughEm",
"[em *][em&strikethrough ~~foo~~][em *]");

MT("strikethroughStrong",
"[strikethrough ~~][strong&strikethrough **foo**][strikethrough ~~]");

MT("strikethroughStrong",
"[strong **][strong&strikethrough ~~foo~~][strong **]");

})();
4 changes: 2 additions & 2 deletions mode/htmlmixed/htmlmixed.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
if (stream.match(/^<\/\s*script\s*>/i, false)) {
state.token = html;
state.localState = state.localMode = null;
return html(stream, state);
return null;
}
return maybeBackup(stream, /<\/\s*script\s*>/,
state.localMode.token(stream, state.localState));
Expand All @@ -78,7 +78,7 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
if (stream.match(/^<\/\s*style\s*>/i, false)) {
state.token = html;
state.localState = state.localMode = null;
return html(stream, state);
return null;
}
return maybeBackup(stream, /<\/\s*style\s*>/,
cssMode.token(stream, state.localState));
Expand Down
290 changes: 290 additions & 0 deletions mode/idl/idl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

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

function wordRegexp(words) {
return new RegExp('^((' + words.join(')|(') + '))\\b', 'i');
};

var builtinArray = [
'a_correlate', 'abs', 'acos', 'adapt_hist_equal', 'alog',
'alog2', 'alog10', 'amoeba', 'annotate', 'app_user_dir',
'app_user_dir_query', 'arg_present', 'array_equal', 'array_indices',
'arrow', 'ascii_template', 'asin', 'assoc', 'atan',
'axis', 'axis', 'bandpass_filter', 'bandreject_filter', 'barplot',
'bar_plot', 'beseli', 'beselj', 'beselk', 'besely',
'beta', 'biginteger', 'bilinear', 'bin_date', 'binary_template',
'bindgen', 'binomial', 'bit_ffs', 'bit_population', 'blas_axpy',
'blk_con', 'boolarr', 'boolean', 'boxplot', 'box_cursor',
'breakpoint', 'broyden', 'bubbleplot', 'butterworth', 'bytarr',
'byte', 'byteorder', 'bytscl', 'c_correlate', 'calendar',
'caldat', 'call_external', 'call_function', 'call_method',
'call_procedure', 'canny', 'catch', 'cd', 'cdf', 'ceil',
'chebyshev', 'check_math', 'chisqr_cvf', 'chisqr_pdf', 'choldc',
'cholsol', 'cindgen', 'cir_3pnt', 'clipboard', 'close',
'clust_wts', 'cluster', 'cluster_tree', 'cmyk_convert', 'code_coverage',
'color_convert', 'color_exchange', 'color_quan', 'color_range_map',
'colorbar', 'colorize_sample', 'colormap_applicable',
'colormap_gradient', 'colormap_rotation', 'colortable',
'comfit', 'command_line_args', 'common', 'compile_opt', 'complex',
'complexarr', 'complexround', 'compute_mesh_normals', 'cond', 'congrid',
'conj', 'constrained_min', 'contour', 'contour', 'convert_coord',
'convol', 'convol_fft', 'coord2to3', 'copy_lun', 'correlate',
'cos', 'cosh', 'cpu', 'cramer', 'createboxplotdata',
'create_cursor', 'create_struct', 'create_view', 'crossp', 'crvlength',
'ct_luminance', 'cti_test', 'cursor', 'curvefit', 'cv_coord',
'cvttobm', 'cw_animate', 'cw_animate_getp', 'cw_animate_load',
'cw_animate_run', 'cw_arcball', 'cw_bgroup', 'cw_clr_index',
'cw_colorsel', 'cw_defroi', 'cw_field', 'cw_filesel', 'cw_form',
'cw_fslider', 'cw_light_editor', 'cw_light_editor_get',
'cw_light_editor_set', 'cw_orient', 'cw_palette_editor',
'cw_palette_editor_get', 'cw_palette_editor_set', 'cw_pdmenu',
'cw_rgbslider', 'cw_tmpl', 'cw_zoom', 'db_exists',
'dblarr', 'dcindgen', 'dcomplex', 'dcomplexarr', 'define_key',
'define_msgblk', 'define_msgblk_from_file', 'defroi', 'defsysv',
'delvar', 'dendro_plot', 'dendrogram', 'deriv', 'derivsig',
'determ', 'device', 'dfpmin', 'diag_matrix', 'dialog_dbconnect',
'dialog_message', 'dialog_pickfile', 'dialog_printersetup',
'dialog_printjob', 'dialog_read_image',
'dialog_write_image', 'dictionary', 'digital_filter', 'dilate', 'dindgen',
'dissolve', 'dist', 'distance_measure', 'dlm_load', 'dlm_register',
'doc_library', 'double', 'draw_roi', 'edge_dog', 'efont',
'eigenql', 'eigenvec', 'ellipse', 'elmhes', 'emboss',
'empty', 'enable_sysrtn', 'eof', 'eos', 'erase',
'erf', 'erfc', 'erfcx', 'erode', 'errorplot',
'errplot', 'estimator_filter', 'execute', 'exit', 'exp',
'expand', 'expand_path', 'expint', 'extrac', 'extract_slice',
'f_cvf', 'f_pdf', 'factorial', 'fft', 'file_basename',
'file_chmod', 'file_copy', 'file_delete', 'file_dirname',
'file_expand_path', 'file_gunzip', 'file_gzip', 'file_info',
'file_lines', 'file_link', 'file_mkdir', 'file_move',
'file_poll_input', 'file_readlink', 'file_same',
'file_search', 'file_tar', 'file_test', 'file_untar', 'file_unzip',
'file_which', 'file_zip', 'filepath', 'findgen', 'finite',
'fix', 'flick', 'float', 'floor', 'flow3',
'fltarr', 'flush', 'format_axis_values', 'forward_function', 'free_lun',
'fstat', 'fulstr', 'funct', 'function', 'fv_test',
'fx_root', 'fz_roots', 'gamma', 'gamma_ct', 'gauss_cvf',
'gauss_pdf', 'gauss_smooth', 'gauss2dfit', 'gaussfit',
'gaussian_function', 'gaussint', 'get_drive_list', 'get_dxf_objects',
'get_kbrd', 'get_login_info',
'get_lun', 'get_screen_size', 'getenv', 'getwindows', 'greg2jul',
'grib', 'grid_input', 'grid_tps', 'grid3', 'griddata',
'gs_iter', 'h_eq_ct', 'h_eq_int', 'hanning', 'hash',
'hdf', 'hdf5', 'heap_free', 'heap_gc', 'heap_nosave',
'heap_refcount', 'heap_save', 'help', 'hilbert', 'hist_2d',
'hist_equal', 'histogram', 'hls', 'hough', 'hqr',
'hsv', 'i18n_multibytetoutf8',
'i18n_multibytetowidechar', 'i18n_utf8tomultibyte',
'i18n_widechartomultibyte',
'ibeta', 'icontour', 'iconvertcoord', 'idelete', 'identity',
'idl_base64', 'idl_container', 'idl_validname',
'idlexbr_assistant', 'idlitsys_createtool',
'idlunit', 'iellipse', 'igamma', 'igetcurrent', 'igetdata',
'igetid', 'igetproperty', 'iimage', 'image', 'image_cont',
'image_statistics', 'image_threshold', 'imaginary', 'imap', 'indgen',
'int_2d', 'int_3d', 'int_tabulated', 'intarr', 'interpol',
'interpolate', 'interval_volume', 'invert', 'ioctl', 'iopen',
'ir_filter', 'iplot', 'ipolygon', 'ipolyline', 'iputdata',
'iregister', 'ireset', 'iresolve', 'irotate', 'isa',
'isave', 'iscale', 'isetcurrent', 'isetproperty', 'ishft',
'isocontour', 'isosurface', 'isurface', 'itext', 'itranslate',
'ivector', 'ivolume', 'izoom', 'journal', 'json_parse',
'json_serialize', 'jul2greg', 'julday', 'keyword_set', 'krig2d',
'kurtosis', 'kw_test', 'l64indgen', 'la_choldc', 'la_cholmprove',
'la_cholsol', 'la_determ', 'la_eigenproblem', 'la_eigenql', 'la_eigenvec',
'la_elmhes', 'la_gm_linear_model', 'la_hqr', 'la_invert',
'la_least_square_equality', 'la_least_squares', 'la_linear_equation',
'la_ludc', 'la_lumprove', 'la_lusol',
'la_svd', 'la_tridc', 'la_trimprove', 'la_triql', 'la_trired',
'la_trisol', 'label_date', 'label_region', 'ladfit', 'laguerre',
'lambda', 'lambdap', 'lambertw', 'laplacian', 'least_squares_filter',
'leefilt', 'legend', 'legendre', 'linbcg', 'lindgen',
'linfit', 'linkimage', 'list', 'll_arc_distance', 'lmfit',
'lmgr', 'lngamma', 'lnp_test', 'loadct', 'locale_get',
'logical_and', 'logical_or', 'logical_true', 'lon64arr', 'lonarr',
'long', 'long64', 'lsode', 'lu_complex', 'ludc',
'lumprove', 'lusol', 'm_correlate', 'machar', 'make_array',
'make_dll', 'make_rt', 'map', 'mapcontinents', 'mapgrid',
'map_2points', 'map_continents', 'map_grid', 'map_image', 'map_patch',
'map_proj_forward', 'map_proj_image', 'map_proj_info',
'map_proj_init', 'map_proj_inverse',
'map_set', 'matrix_multiply', 'matrix_power', 'max', 'md_test',
'mean', 'meanabsdev', 'mean_filter', 'median', 'memory',
'mesh_clip', 'mesh_decimate', 'mesh_issolid',
'mesh_merge', 'mesh_numtriangles',
'mesh_obj', 'mesh_smooth', 'mesh_surfacearea',
'mesh_validate', 'mesh_volume',
'message', 'min', 'min_curve_surf', 'mk_html_help', 'modifyct',
'moment', 'morph_close', 'morph_distance',
'morph_gradient', 'morph_hitormiss',
'morph_open', 'morph_thin', 'morph_tophat', 'multi', 'n_elements',
'n_params', 'n_tags', 'ncdf', 'newton', 'noise_hurl',
'noise_pick', 'noise_scatter', 'noise_slur', 'norm', 'obj_class',
'obj_destroy', 'obj_hasmethod', 'obj_isa', 'obj_new', 'obj_valid',
'objarr', 'on_error', 'on_ioerror', 'online_help', 'openr',
'openu', 'openw', 'oplot', 'oploterr', 'orderedhash',
'p_correlate', 'parse_url', 'particle_trace', 'path_cache', 'path_sep',
'pcomp', 'plot', 'plot3d', 'plot', 'plot_3dbox',
'plot_field', 'ploterr', 'plots', 'polar_contour', 'polar_surface',
'polyfill', 'polyshade', 'pnt_line', 'point_lun', 'polarplot',
'poly', 'poly_2d', 'poly_area', 'poly_fit', 'polyfillv',
'polygon', 'polyline', 'polywarp', 'popd', 'powell',
'pref_commit', 'pref_get', 'pref_set', 'prewitt', 'primes',
'print', 'printf', 'printd', 'pro', 'product',
'profile', 'profiler', 'profiles', 'project_vol', 'ps_show_fonts',
'psafm', 'pseudo', 'ptr_free', 'ptr_new', 'ptr_valid',
'ptrarr', 'pushd', 'qgrid3', 'qhull', 'qromb',
'qromo', 'qsimp', 'query_*', 'query_ascii', 'query_bmp',
'query_csv', 'query_dicom', 'query_gif', 'query_image', 'query_jpeg',
'query_jpeg2000', 'query_mrsid', 'query_pict', 'query_png', 'query_ppm',
'query_srf', 'query_tiff', 'query_video', 'query_wav', 'r_correlate',
'r_test', 'radon', 'randomn', 'randomu', 'ranks',
'rdpix', 'read', 'readf', 'read_ascii', 'read_binary',
'read_bmp', 'read_csv', 'read_dicom', 'read_gif', 'read_image',
'read_interfile', 'read_jpeg', 'read_jpeg2000', 'read_mrsid', 'read_pict',
'read_png', 'read_ppm', 'read_spr', 'read_srf', 'read_sylk',
'read_tiff', 'read_video', 'read_wav', 'read_wave', 'read_x11_bitmap',
'read_xwd', 'reads', 'readu', 'real_part', 'rebin',
'recall_commands', 'recon3', 'reduce_colors', 'reform', 'region_grow',
'register_cursor', 'regress', 'replicate',
'replicate_inplace', 'resolve_all',
'resolve_routine', 'restore', 'retall', 'return', 'reverse',
'rk4', 'roberts', 'rot', 'rotate', 'round',
'routine_filepath', 'routine_info', 'rs_test', 's_test', 'save',
'savgol', 'scale3', 'scale3d', 'scatterplot', 'scatterplot3d',
'scope_level', 'scope_traceback', 'scope_varfetch',
'scope_varname', 'search2d',
'search3d', 'sem_create', 'sem_delete', 'sem_lock', 'sem_release',
'set_plot', 'set_shading', 'setenv', 'sfit', 'shade_surf',
'shade_surf_irr', 'shade_volume', 'shift', 'shift_diff', 'shmdebug',
'shmmap', 'shmunmap', 'shmvar', 'show3', 'showfont',
'signum', 'simplex', 'sin', 'sindgen', 'sinh',
'size', 'skewness', 'skip_lun', 'slicer3', 'slide_image',
'smooth', 'sobel', 'socket', 'sort', 'spawn',
'sph_4pnt', 'sph_scat', 'spher_harm', 'spl_init', 'spl_interp',
'spline', 'spline_p', 'sprsab', 'sprsax', 'sprsin',
'sprstp', 'sqrt', 'standardize', 'stddev', 'stop',
'strarr', 'strcmp', 'strcompress', 'streamline', 'streamline',
'stregex', 'stretch', 'string', 'strjoin', 'strlen',
'strlowcase', 'strmatch', 'strmessage', 'strmid', 'strpos',
'strput', 'strsplit', 'strtrim', 'struct_assign', 'struct_hide',
'strupcase', 'surface', 'surface', 'surfr', 'svdc',
'svdfit', 'svsol', 'swap_endian', 'swap_endian_inplace', 'symbol',
'systime', 't_cvf', 't_pdf', 't3d', 'tag_names',
'tan', 'tanh', 'tek_color', 'temporary', 'terminal_size',
'tetra_clip', 'tetra_surface', 'tetra_volume', 'text', 'thin',
'thread', 'threed', 'tic', 'time_test2', 'timegen',
'timer', 'timestamp', 'timestamptovalues', 'tm_test', 'toc',
'total', 'trace', 'transpose', 'tri_surf', 'triangulate',
'trigrid', 'triql', 'trired', 'trisol', 'truncate_lun',
'ts_coef', 'ts_diff', 'ts_fcast', 'ts_smooth', 'tv',
'tvcrs', 'tvlct', 'tvrd', 'tvscl', 'typename',
'uindgen', 'uint', 'uintarr', 'ul64indgen', 'ulindgen',
'ulon64arr', 'ulonarr', 'ulong', 'ulong64', 'uniq',
'unsharp_mask', 'usersym', 'value_locate', 'variance', 'vector',
'vector_field', 'vel', 'velovect', 'vert_t3d', 'voigt',
'volume', 'voronoi', 'voxel_proj', 'wait', 'warp_tri',
'watershed', 'wdelete', 'wf_draw', 'where', 'widget_base',
'widget_button', 'widget_combobox', 'widget_control',
'widget_displaycontextmenu', 'widget_draw',
'widget_droplist', 'widget_event', 'widget_info',
'widget_label', 'widget_list',
'widget_propertysheet', 'widget_slider', 'widget_tab',
'widget_table', 'widget_text',
'widget_tree', 'widget_tree_move', 'widget_window',
'wiener_filter', 'window',
'window', 'write_bmp', 'write_csv', 'write_gif', 'write_image',
'write_jpeg', 'write_jpeg2000', 'write_nrif', 'write_pict', 'write_png',
'write_ppm', 'write_spr', 'write_srf', 'write_sylk', 'write_tiff',
'write_video', 'write_wav', 'write_wave', 'writeu', 'wset',
'wshow', 'wtn', 'wv_applet', 'wv_cwt', 'wv_cw_wavelet',
'wv_denoise', 'wv_dwt', 'wv_fn_coiflet',
'wv_fn_daubechies', 'wv_fn_gaussian',
'wv_fn_haar', 'wv_fn_morlet', 'wv_fn_paul',
'wv_fn_symlet', 'wv_import_data',
'wv_import_wavelet', 'wv_plot3d_wps', 'wv_plot_multires',
'wv_pwt', 'wv_tool_denoise',
'xbm_edit', 'xdisplayfile', 'xdxf', 'xfont', 'xinteranimate',
'xloadct', 'xmanager', 'xmng_tmpl', 'xmtool', 'xobjview',
'xobjview_rotate', 'xobjview_write_image',
'xpalette', 'xpcolor', 'xplot3d',
'xregistered', 'xroi', 'xsq_test', 'xsurface', 'xvaredit',
'xvolume', 'xvolume_rotate', 'xvolume_write_image',
'xyouts', 'zlib_compress', 'zlib_uncompress', 'zoom', 'zoom_24'
];
var builtins = wordRegexp(builtinArray);

var keywordArray = [
'begin', 'end', 'endcase', 'endfor',
'endwhile', 'endif', 'endrep', 'endforeach',
'break', 'case', 'continue', 'for',
'foreach', 'goto', 'if', 'then', 'else',
'repeat', 'until', 'switch', 'while',
'do', 'pro', 'function'
];
var keywords = wordRegexp(keywordArray);

CodeMirror.registerHelper("hintWords", "idl", builtinArray.concat(keywordArray));

var identifiers = new RegExp('^[_a-z\xa1-\uffff][_a-z0-9\xa1-\uffff]*', 'i');

var singleOperators = /[+\-*&=<>\/@#~$]/;
var boolOperators = new RegExp('(and|or|eq|lt|le|gt|ge|ne|not)', 'i');

function tokenBase(stream) {
// whitespaces
if (stream.eatSpace()) return null;

// Handle one line Comments
if (stream.match(';')) {
stream.skipToEnd();
return 'comment';
}

// Handle Number Literals
if (stream.match(/^[0-9\.+-]/, false)) {
if (stream.match(/^[+-]?0x[0-9a-fA-F]+/))
return 'number';
if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?/))
return 'number';
if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?/))
return 'number';
}

// Handle Strings
if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; }
if (stream.match(/^'([^']|(''))*'/)) { return 'string'; }

// Handle words
if (stream.match(keywords)) { return 'keyword'; }
if (stream.match(builtins)) { return 'builtin'; }
if (stream.match(identifiers)) { return 'variable'; }

if (stream.match(singleOperators) || stream.match(boolOperators)) {
return 'operator'; }

// Handle non-detected items
stream.next();
return 'error';
};

CodeMirror.defineMode('idl', function() {
return {
token: function(stream) {
return tokenBase(stream);
}
};
});

CodeMirror.defineMIME('text/x-idl', 'idl');
});
64 changes: 64 additions & 0 deletions mode/idl/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!doctype html>

<title>CodeMirror: IDL 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="idl.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"><h1>CodeMirror</h1><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/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">IDL</a>
</ul>
</div>

<article>
<h2>IDL mode</h2>

<div><textarea id="code" name="code">
;; Example IDL code
FUNCTION mean_and_stddev,array
;; This program reads in an array of numbers
;; and returns a structure containing the
;; average and standard deviation

ave = 0.0
count = 0.0

for i=0,N_ELEMENTS(array)-1 do begin
ave = ave + array[i]
count = count + 1
endfor

ave = ave/count

std = stddev(array)

return, {average:ave,std:std}

END

</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "idl",
version: 1,
singleLineStringErrors: false},
lineNumbers: true,
indentUnit: 4,
matchBrackets: true
});
</script>

<p><strong>MIME types defined:</strong> <code>text/x-idl</code>.</p>
</article>
3 changes: 3 additions & 0 deletions mode/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ <h2>Language modes</h2>
<li><a href="python/index.html">Cython</a></li>
<li><a href="d/index.html">D</a></li>
<li><a href="django/index.html">Django</a> (templating language)</li>
<li><a href="dockerfile/index.html">Dockerfile</a></li>
<li><a href="diff/index.html">diff</a></li>
<li><a href="dtd/index.html">DTD</a></li>
<li><a href="dylan/index.html">Dylan</a></li>
Expand All @@ -60,6 +61,7 @@ <h2>Language modes</h2>
<li><a href="htmlembedded/index.html">HTML embedded scripts</a></li>
<li><a href="htmlmixed/index.html">HTML mixed-mode</a></li>
<li><a href="http/index.html">HTTP</a></li>
<li><a href="idl/index.html">IDL</a></li>
<li><a href="clike/index.html">Java</a></li>
<li><a href="jade/index.html">Jade</a></li>
<li><a href="javascript/index.html">JavaScript</a></li>
Expand All @@ -74,6 +76,7 @@ <h2>Language modes</h2>
<li><a href="modelica/index.html">Modelica</a></li>
<li><a href="nginx/index.html">Nginx</a></li>
<li><a href="ntriples/index.html">NTriples</a></li>
<li><a href="clike/index.html">Objective C</a></li>
<li><a href="mllike/index.html">OCaml</a></li>
<li><a href="octave/index.html">Octave</a> (MATLAB)</li>
<li><a href="pascal/index.html">Pascal</a></li>
Expand Down
117 changes: 62 additions & 55 deletions mode/markdown/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror", require("../xml/xml")));
mod(require("../../lib/codemirror", require("../xml/xml"), require("../meta")));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../xml/xml"], mod);
define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
Expand All @@ -15,45 +15,15 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

var htmlFound = CodeMirror.modes.hasOwnProperty("xml");
var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain");
var aliases = {
html: "htmlmixed",
js: "javascript",
json: "application/json",
c: "text/x-csrc",
"c++": "text/x-c++src",
java: "text/x-java",
csharp: "text/x-csharp",
"c#": "text/x-csharp",
scala: "text/x-scala"
};

var getMode = (function () {
var i, modes = {}, mimes = {}, mime;

var list = [];
for (var m in CodeMirror.modes)
if (CodeMirror.modes.propertyIsEnumerable(m)) list.push(m);
for (i = 0; i < list.length; i++) {
modes[list[i]] = list[i];
function getMode(name) {
if (CodeMirror.findModeByName) {
var found = CodeMirror.findModeByName(name);
if (found) name = found.mime || found.mimes[0];
}
var mimesList = [];
for (var m in CodeMirror.mimeModes)
if (CodeMirror.mimeModes.propertyIsEnumerable(m))
mimesList.push({mime: m, mode: CodeMirror.mimeModes[m]});
for (i = 0; i < mimesList.length; i++) {
mime = mimesList[i].mime;
mimes[mime] = mimesList[i].mime;
}

for (var a in aliases) {
if (aliases[a] in modes || aliases[a] in mimes)
modes[a] = aliases[a];
}

return function (lang) {
return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
};
}());
var mode = CodeMirror.getMode(cmCfg, name);
return mode.name == "null" ? null : mode;
}

// Should characters that affect highlighting be highlighted separate?
// Does not include characters that will be output (such as `1.` and `-` for lists)
Expand All @@ -75,6 +45,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
// Turn on task lists? ("- [ ] " and "- [x] ")
if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;

// Turn on strikethrough syntax
if (modeCfg.strikethrough === undefined)
modeCfg.strikethrough = false;

var codeDepth = 0;

var header = 'header'
Expand All @@ -91,15 +65,16 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
, linktext = 'link'
, linkhref = 'string'
, em = 'em'
, strong = 'strong';
, strong = 'strong'
, strikethrough = 'strikethrough';

var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
, ulRE = /^[*\-+]\s+/
, olRE = /^[0-9]+\.\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
, atxHeaderRE = /^#+/
, setextHeaderRE = /^(?:\={1,}|-{1,})$/
, textRE = /^[^#!\[\]*_\\<>` "'(]+/;
, textRE = /^[^#!\[\]*_\\<>` "'(~]+/;

function switchInline(stream, state, f) {
state.f = state.inline = f;
Expand All @@ -121,6 +96,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.em = false;
// Reset STRONG state
state.strong = false;
// Reset strikethrough state
state.strikethrough = false;
// Reset state.quote
state.quote = 0;
if (!htmlFound && state.f == htmlBlock) {
Expand Down Expand Up @@ -197,11 +174,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.f = state.inline;
if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
return getType(state);
} else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
} else if (modeCfg.fencedCodeBlocks && stream.match(/^```[ \t]*([\w+#]*)/, true)) {
// try switching mode
state.localMode = getMode(RegExp.$1);
if (state.localMode) state.localState = state.localMode.startState();
switchBlock(stream, state, local);
state.f = state.block = local;
if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.code = true;
return getType(state);
Expand All @@ -222,15 +199,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}

function local(stream, state) {
if (stream.sol() && stream.match(/^```/, true)) {
if (stream.sol() && stream.match("```", false)) {
state.localMode = state.localState = null;
state.f = inlineNormal;
state.block = blockNormal;
if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.code = true;
var returnType = getType(state);
state.code = false;
return returnType;
state.f = state.block = leavingLocal;
return null;
} else if (state.localMode) {
return state.localMode.token(stream, state.localState);
} else {
Expand All @@ -239,6 +211,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
}

function leavingLocal(stream, state) {
stream.match("```");
state.block = blockNormal;
state.f = inlineNormal;
if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.code = true;
var returnType = getType(state);
state.code = false;
return returnType;
}

// Inline
function getType(state) {
var styles = [];
Expand Down Expand Up @@ -283,6 +266,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

if (state.strong) { styles.push(strong); }
if (state.em) { styles.push(em); }
if (state.strikethrough) { styles.push(strikethrough); }

if (state.linkText) { styles.push(linktext); }

Expand Down Expand Up @@ -511,6 +495,29 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
}

if (modeCfg.strikethrough) {
if (ch === '~' && stream.eatWhile(ch)) {
if (state.strikethrough) {// Remove strikethrough
if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
var t = getType(state);
state.strikethrough = false;
return t;
} else if (stream.match(/^[^\s]/, false)) {// Add strikethrough
state.strikethrough = true;
if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
return getType(state);
}
} else if (ch === ' ') {
if (stream.match(/^~~/, true)) { // Probably surrounded by space
if (stream.peek() === ' ') { // Surrounded by spaces, ignore
return getType(state);
} else { // Not surrounded by spaces, back up pointer
stream.backUp(2);
}
}
}
}

if (ch === ' ') {
if (stream.match(/ +$/, false)) {
state.trailingSpace++;
Expand Down Expand Up @@ -659,7 +666,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
listDepth: 0,
quote: 0,
trailingSpace: 0,
trailingSpaceNewLine: false
trailingSpaceNewLine: false,
strikethrough: false
};
},

Expand All @@ -683,6 +691,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
linkTitle: s.linkTitle,
em: s.em,
strong: s.strong,
strikethrough: s.strikethrough,
header: s.header,
taskList: s.taskList,
list: s.list,
Expand Down Expand Up @@ -733,9 +742,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.indentation = adjustedIndentation;
if (indentation > 0) return null;
}
var result = state.f(stream, state);
if (stream.start == stream.pos) return this.token(stream, state);
else return result;
return state.f(stream, state);
},

innerMode: function(state) {
Expand Down
60 changes: 38 additions & 22 deletions mode/meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,28 @@
{name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]},
{name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk"},
{name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]},
{name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "hpp", "h++"]},
{name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "hpp", "h++"], alias: ["cpp"]},
{name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
{name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"]},
{name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
{name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]},
{name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"]},
{name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"]},
{name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
{name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
{name: "Cypher", mime: "application/x-cypher-query", mode: "cypher"},
{name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]},
{name: "CSS", mime: "text/css", mode: "css", ext: ["css"]},
{name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]},
{name: "D", mime: "text/x-d", mode: "d", ext: ["d"]},
{name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]},
{name: "Django", mime: "text/x-django", mode: "django"},
{name: "Dockerfile", mime: "text/x-dockerfile", mode: "dockerfile"},
{name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]},
{name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
{name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
{name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
{name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
{name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
{name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]},
{name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"]},
{name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
{name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
{name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
{name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm"},
Expand All @@ -44,21 +46,22 @@
{name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
{name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
{name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
{name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"]},
{name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"]},
{name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
{name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]},
{name: "HTTP", mime: "message/http", mode: "http"},
{name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
{name: "Jade", mime: "text/x-jade", mode: "jade", ext: ["jade"]},
{name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
{name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"]},
{name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]},
{name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
mode: "javascript", ext: ["js"]},
{name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"]},
{name: "JSON-LD", mime: "application/ld+json", mode: "javascript"},
mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]},
{name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
{name: "JSON-LD", mime: "application/ld+json", mode: "javascript", alias: ["jsonld"]},
{name: "Jinja2", mime: "null", mode: "jinja2"},
{name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
{name: "Kotlin", mime: "text/x-kotlin", mode: "kotlin", ext: ["kt"]},
{name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
{name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"]},
{name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"], alias: ["ls"]},
{name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]},
{name: "Markdown (GitHub-flavour)", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
{name: "mIRC", mime: "text/mirc", mode: "mirc"},
Expand All @@ -68,6 +71,7 @@
{name: "MySQL", mime: "text/x-mysql", mode: "sql"},
{name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx"},
{name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]},
{name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"]},
{name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
{name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
{name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
Expand All @@ -77,30 +81,32 @@
{name: "Pig", mime: "text/x-pig", mode: "pig"},
{name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
{name: "PLSQL", mime: "text/x-plsql", mode: "sql"},
{name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"]},
{name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
{name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]},
{name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
{name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
{name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"]},
{name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"]},
{name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"]},
{name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]},
{name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]},
{name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"},
{name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]},
{name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]},
{name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
{name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
{name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
{name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
{name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]},
{name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"]},
{name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"]},
{name: "Sieve", mime: "application/sieve", mode: "sieve"},
{name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim"},
{name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
{name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
{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", ext: ["sparql"]},
{name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]},
{name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
{name: "MariaDB", mime: "text/x-mariadb", mode: "sql"},
{name: "sTeX", mime: "text/x-stex", mode: "stex"},
{name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"]},
{name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]},
{name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]},
{name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
{name: "Textile", mime: "text/x-textile", mode: "textile"},
Expand All @@ -109,14 +115,14 @@
{name: "TOML", mime: "text/x-toml", mode: "toml"},
{name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
{name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
{name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"]},
{name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]},
{name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
{name: "VBScript", mime: "text/vbscript", mode: "vbscript"},
{name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
{name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
{name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"]},
{name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]},
{name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
{name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml"]},
{name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml"], alias: ["yml"]},
{name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]}
];
// Ensure all modes have a mime property for backwards compatibility
Expand All @@ -141,4 +147,14 @@
if (info.ext[j] == ext) return info;
}
};

CodeMirror.findModeByName = function(name) {
name = name.toLowerCase();
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
var info = CodeMirror.modeInfo[i];
if (info.name.toLowerCase() == name) return info;
if (info.alias) for (var j = 0; j < info.alias.length; j++)
if (info.alias[j].toLowerCase() == name) return info;
}
};
});
3 changes: 1 addition & 2 deletions mode/ruby/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ <h2>Ruby mode</h2>
<p><strong>MIME types defined:</strong> <code>text/x-ruby</code>.</p>

<p>Development of the CodeMirror Ruby mode was kindly sponsored
by <a href="http://ubalo.com/">Ubalo</a>, who hold
the <a href="LICENSE">license</a>.</p>
by <a href="http://ubalo.com/">Ubalo</a>.</p>

</article>
20 changes: 14 additions & 6 deletions mode/sparql/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,33 @@ <h2>SPARQL mode</h2>
PREFIX a: &lt;http://www.w3.org/2000/10/annotation-ns#>
PREFIX dc: &lt;http://purl.org/dc/elements/1.1/>
PREFIX foaf: &lt;http://xmlns.com/foaf/0.1/>
PREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#>

# Comment!

SELECT ?given ?family
WHERE {
?annot a:annotates &lt;http://www.w3.org/TR/rdf-sparql-query/> .
?annot dc:creator ?c .
OPTIONAL {?c foaf:given ?given ;
foaf:family ?family } .
{
?annot a:annotates &lt;http://www.w3.org/TR/rdf-sparql-query/> .
?annot dc:creator ?c .
OPTIONAL {?c foaf:givenName ?given ;
foaf:familyName ?family }
} UNION {
?c !foaf:knows/foaf:knows? ?thing.
?thing rdfs
} MINUS {
?thing rdfs:label "剛柔流"@jp
}
FILTER isBlank(?c)
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: "application/x-sparql-query",
mode: "application/sparql-query",
matchBrackets: true
});
</script>

<p><strong>MIME types defined:</strong> <code>application/x-sparql-query</code>.</p>
<p><strong>MIME types defined:</strong> <code>application/sparql-query</code>.</p>

</article>
24 changes: 19 additions & 5 deletions mode/sparql/sparql.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,28 @@ CodeMirror.defineMode("sparql", function(config) {
return new RegExp("^(?:" + words.join("|") + ")$", "i");
}
var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
"iri", "uri", "bnode", "count", "sum", "min", "max", "avg", "sample",
"group_concat", "rand", "abs", "ceil", "floor", "round", "concat", "substr", "strlen",
"replace", "ucase", "lcase", "encode_for_uri", "contains", "strstarts", "strends",
"strbefore", "strafter", "year", "month", "day", "hours", "minutes", "seconds",
"timezone", "tz", "now", "uuid", "struuid", "md5", "sha1", "sha256", "sha384",
"sha512", "coalesce", "if", "strlang", "strdt", "isnumeric", "regex", "exists",
"isblank", "isliteral", "a"]);
var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
"ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
"graph", "by", "asc", "desc", "as", "having", "undef", "values", "group",
"minus", "in", "not", "service", "silent", "using", "insert", "delete", "union",
"true", "false", "with",
"data", "copy", "to", "move", "add", "create", "drop", "clear", "load"]);
var operatorChars = /[*+\-<>=&|]/;
var operatorChars = /[*+\-<>=&|\^\/!\?]/;

function tokenBase(stream, state) {
var ch = stream.next();
curPunc = null;
if (ch == "$" || ch == "?") {
if(ch == "?" && stream.match(/\s/, false)){
return "operator";
}
stream.match(/^[\w\d]*/);
return "variable-2";
}
Expand All @@ -44,20 +54,24 @@ CodeMirror.defineMode("sparql", function(config) {
}
else if (/[{}\(\),\.;\[\]]/.test(ch)) {
curPunc = ch;
return null;
return "bracket";
}
else if (ch == "#") {
stream.skipToEnd();
return "comment";
}
else if (operatorChars.test(ch)) {
stream.eatWhile(operatorChars);
return null;
return "operator";
}
else if (ch == ":") {
stream.eatWhile(/[\w\d\._\-]/);
return "atom";
}
else if (ch == "@") {
stream.eatWhile(/[a-z\d\-]/i);
return "meta";
}
else {
stream.eatWhile(/[_\w\d]/);
if (stream.eat(":")) {
Expand All @@ -66,7 +80,7 @@ CodeMirror.defineMode("sparql", function(config) {
}
var word = stream.current();
if (ops.test(word))
return null;
return "builtin";
else if (keywords.test(word))
return "keyword";
else
Expand Down Expand Up @@ -155,6 +169,6 @@ CodeMirror.defineMode("sparql", function(config) {
};
});

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

});
2 changes: 0 additions & 2 deletions mode/sql/sql.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,6 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
keywords:
A list of keywords you want to be highlighted.
functions:
A list of function names you want to be highlighted.
builtin:
A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword").
operatorChars:
Expand Down
377 changes: 184 additions & 193 deletions mode/stex/stex.js

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion mode/yaml/yaml.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,13 @@ CodeMirror.defineMode("yaml", function() {
state.escaped = false;
/* comments */
if (ch == "#" && (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))) {
stream.skipToEnd(); return "comment";
stream.skipToEnd();
return "comment";
}

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

if (state.literal && stream.indentation() > state.keyCol) {
stream.skipToEnd(); return "string";
} else if (state.literal) { state.literal = false; }
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codemirror",
"version":"4.7.0",
"version":"4.8.0",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [{"type": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion test/lint/lint.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var topAllowedGlobals = Object.create(null);
"screen FileReader Worker postMessage importScripts " +
"setInterval clearInterval setTimeout clearTimeout " +
"CodeMirror " +
"test exports require module define")
"test exports require module define requirejs")
.split(" ").forEach(function(n) { topAllowedGlobals[n] = true; });

var fs = require("fs"), acorn = require("./acorn.js"), walk = require("./walk.js");
Expand Down
43 changes: 42 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var Pos = CodeMirror.Pos;
CodeMirror.defaults.rtlMoveVisually = true;

function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i], i);
}

function addDoc(cm, width, height) {
Expand Down Expand Up @@ -1975,6 +1975,18 @@ testCM("alwaysMergeSelEventWithChangeOrigin", function(cm) {
eq(cm.getValue(), "Va");
}, {value: "a"});

testCM("getTokenAt", function(cm) {
var tokPlus = cm.getTokenAt(Pos(0, 2));
eq(tokPlus.type, "operator");
eq(tokPlus.string, "+");
var toks = cm.getLineTokens(0);
eq(toks.length, 3);
forEach([["number", "1"], ["operator", "+"], ["number", "2"]], function(expect, i) {
eq(toks[i].type, expect[0]);
eq(toks[i].string, expect[1]);
});
}, {value: "1+2", mode: "javascript"});

testCM("getTokenTypeAt", function(cm) {
eq(cm.getTokenTypeAt(Pos(0, 0)), "number");
eq(cm.getTokenTypeAt(Pos(0, 6)), "string");
Expand Down Expand Up @@ -2032,3 +2044,32 @@ testCM("eventOrder", function(cm) {
cm.replaceSelection("/");
eq(seen.join(","), "change,change,activity,change");
});

test("core_rmClass", function() {
var node = document.createElement("div");
node.className = "foo-bar baz-quux yadda";
CodeMirror.rmClass(node, "quux");
eq(node.className, "foo-bar baz-quux yadda");
CodeMirror.rmClass(node, "baz-quux");
eq(node.className, "foo-bar yadda");
CodeMirror.rmClass(node, "yadda");
eq(node.className, "foo-bar");
CodeMirror.rmClass(node, "foo-bar");
eq(node.className, "");
node.className = " foo ";
CodeMirror.rmClass(node, "foo");
eq(node.className, "");
});

test("core_addClass", function() {
var node = document.createElement("div");
CodeMirror.addClass(node, "a");
eq(node.className, "a");
CodeMirror.addClass(node, "a");
eq(node.className, "a");
CodeMirror.addClass(node, "b");
eq(node.className, "a b");
CodeMirror.addClass(node, "a");
CodeMirror.addClass(node, "b");
eq(node.className, "a b");
});
160 changes: 136 additions & 24 deletions test/vim_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ function testVim(name, run, opts, expectedFail) {
for (var i = 0; i < arguments.length; i++) {
var key = arguments[i];
// Find key in keymap and handle.
var handled = CodeMirror.lookupKey(key, ['vim-insert'], executeHandler);
var handled = CodeMirror.lookupKey(key, 'vim-insert', executeHandler);
// Record for insert mode.
if (handled === true && cm.state.vim.insertMode && arguments[i] != 'Esc') {
if (handled == "handled" && cm.state.vim.insertMode && arguments[i] != 'Esc') {
var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges;
if (lastChange) {
lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key));
Expand Down Expand Up @@ -898,32 +898,36 @@ testVim('cc_multiply_repeat', function(cm, vim, helpers) {
is(register.linewise);
eq('vim-insert', cm.getOption('keyMap'));
});
testVim('cc_append', function(cm, vim, helpers) {
testVim('cc_should_not_append_to_document', function(cm, vim, helpers) {
var expectedLineCount = cm.lineCount();
cm.setCursor(cm.lastLine(), 0);
helpers.doKeys('c', 'c');
eq(expectedLineCount, cm.lineCount());
});
function fillArray(val, times) {
var arr = [];
for (var i = 0; i < times; i++) {
arr.push(val);
}
return arr;
}
testVim('c_visual_block', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'l', 'c');
var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' ');
replacement.pop();
var replacement = fillArray('hello', 3);
cm.replaceSelections(replacement);
eq('1hello\n5hello\nahellofg', cm.getValue());
helpers.doKeys('<Esc>');
cm.setCursor(2, 3);
helpers.doKeys('<C-v>', '2', 'k', 'h', 'C');
replacement = new Array(cm.listSelections().length+1).join('world ').split(' ');
replacement.pop();
replacement = fillArray('world', 3);
cm.replaceSelections(replacement);
eq('1hworld\n5hworld\nahworld', cm.getValue());
}, {value: '1234\n5678\nabcdefg'});
testVim('c_visual_block_replay', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('<C-v>', '2', 'j', 'l', 'c');
var replacement = new Array(cm.listSelections().length+1).join('fo ').split(' ');
replacement.pop();
var replacement = fillArray('fo', 3);
cm.replaceSelections(replacement);
eq('1fo4\n5fo8\nafodefg', cm.getValue());
helpers.doKeys('<Esc>');
Expand All @@ -932,6 +936,17 @@ testVim('c_visual_block_replay', function(cm, vim, helpers) {
eq('foo4\nfoo8\nfoodefg', cm.getValue());
}, {value: '1234\n5678\nabcdefg'});

testVim('d_visual_block', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'l', 'd');
eq('1\n5\nafg', cm.getValue());
}, {value: '1234\n5678\nabcdefg'});
testVim('D_visual_block', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('<C-v>', '2', 'j', 'l', 'D');
eq('1\n5\na', cm.getValue());
}, {value: '1234\n5678\nabcdefg'});

// Swapcase commands edit in place and do not modify registers.
testVim('g~w_repeat', function(cm, vim, helpers) {
// Assert that dw does delete newline if it should go to the next line, and
Expand All @@ -955,8 +970,34 @@ testVim('g~g~', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister();
eq('', register.toString());
is(!register.linewise);
eqPos({line: curStart.line, ch:0}, cm.getCursor());
eqPos(curStart, cm.getCursor());
}, { value: ' word1\nword2\nword3\nword4\nword5\nword6' });
testVim('gu_and_gU', function(cm, vim, helpers) {
var curStart = makeCursor(0, 7);
var value = cm.getValue();
cm.setCursor(curStart);
helpers.doKeys('2', 'g', 'U', 'w');
eq(cm.getValue(), 'wa wb xX WC wd');
eqPos(curStart, cm.getCursor());
helpers.doKeys('2', 'g', 'u', 'w');
eq(cm.getValue(), value);

helpers.doKeys('2', 'g', 'U', 'B');
eq(cm.getValue(), 'wa WB Xx wc wd');
eqPos(makeCursor(0, 3), cm.getCursor());

cm.setCursor(makeCursor(0, 4));
helpers.doKeys('g', 'u', 'i', 'w');
eq(cm.getValue(), 'wa wb Xx wc wd');
eqPos(makeCursor(0, 3), cm.getCursor());

// TODO: support gUgU guu
// eqPos(makeCursor(0, 0), cm.getCursor());

var register = helpers.getRegisterController().getRegister();
eq('', register.toString());
is(!register.linewise);
}, { value: 'wa wb xx wc wd' });
testVim('visual_block_~', function(cm, vim, helpers) {
cm.setCursor(1, 1);
helpers.doKeys('<C-v>', 'l', 'l', 'j', '~');
Expand Down Expand Up @@ -1237,7 +1278,7 @@ testVim('a_eol', function(cm, vim, helpers) {
helpers.assertCursorAt(0, lines[0].length);
eq('vim-insert', cm.getOption('keyMap'));
});
testVim('a_endOfSelectedArea', function(cm, vim, helpers) {
testVim('A_endOfSelectedArea', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('v', 'j', 'l');
helpers.doKeys('A');
Expand Down Expand Up @@ -1278,6 +1319,11 @@ testVim('A_visual_block', function(cm, vim, helpers) {
replacement.pop();
cm.replaceSelections(replacement);
eq('testhello\nmehello\npleahellose', cm.getValue());
helpers.doKeys('<Esc>');
cm.setCursor(0, 0);
helpers.doKeys('.');
// TODO this doesn't work yet
// eq('teshellothello\nme hello hello\nplehelloahellose', cm.getValue());
}, {value: 'test\nme\nplease'});
testVim('I', function(cm, vim, helpers) {
cm.setCursor(0, 4);
Expand Down Expand Up @@ -1695,29 +1741,75 @@ testVim('visual', function(cm, vim, helpers) {
helpers.doKeys('d');
eq('15', cm.getValue());
}, { value: '12345' });
testVim('visual_yank', function(cm, vim, helpers) {
helpers.doKeys('v', '3', 'l', 'y');
helpers.assertCursorAt(0, 0);
helpers.doKeys('p');
eq('aa te test for yank', cm.getValue());
}, { value: 'a test for yank' })
testVim('visual_w', function(cm, vim, helpers) {
helpers.doKeys('v', 'w');
eq(cm.getSelection(), 'motion t');
}, { value: 'motion test'});
testVim('visual_initial_selection', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('v');
cm.getSelection('n');
}, { value: 'init'});
testVim('visual_crossover_left', function(cm, vim, helpers) {
cm.setCursor(0, 2);
helpers.doKeys('v', 'l', 'h', 'h');
cm.getSelection('ro');
}, { value: 'cross'});
testVim('visual_crossover_left', function(cm, vim, helpers) {
cm.setCursor(0, 2);
helpers.doKeys('v', 'h', 'l', 'l');
cm.getSelection('os');
}, { value: 'cross'});
testVim('visual_crossover_up', function(cm, vim, helpers) {
cm.setCursor(3, 2);
helpers.doKeys('v', 'j', 'k', 'k');
eqPos(Pos(2, 2), cm.getCursor('head'));
eqPos(Pos(3, 3), cm.getCursor('anchor'));
helpers.doKeys('k');
eqPos(Pos(1, 2), cm.getCursor('head'));
eqPos(Pos(3, 3), cm.getCursor('anchor'));
}, { value: 'cross\ncross\ncross\ncross\ncross\n'});
testVim('visual_crossover_down', function(cm, vim, helpers) {
cm.setCursor(1, 2);
helpers.doKeys('v', 'k', 'j', 'j');
eqPos(Pos(2, 3), cm.getCursor('head'));
eqPos(Pos(1, 2), cm.getCursor('anchor'));
helpers.doKeys('j');
eqPos(Pos(3, 3), cm.getCursor('head'));
eqPos(Pos(1, 2), cm.getCursor('anchor'));
}, { value: 'cross\ncross\ncross\ncross\ncross\n'});
testVim('visual_exit', function(cm, vim, helpers) {
helpers.doKeys('<C-v>', 'l', 'j', 'j', '<Esc>');
eq(cm.getCursor('anchor'), cm.getCursor('head'));
eqPos(cm.getCursor('anchor'), cm.getCursor('head'));
eq(vim.visualMode, false);
}, { value: 'hello\nworld\nfoo' });
testVim('visual_line', function(cm, vim, helpers) {
helpers.doKeys('l', 'V', 'l', 'j', 'j', 'd');
eq(' 4\n 5', cm.getValue());
}, { value: ' 1\n 2\n 3\n 4\n 5' });
testVim('visual_block', function(cm, vim, helpers) {
testVim('visual_block_different_line_lengths', function(cm, vim, helpers) {
// test the block selection with lines of different length
// i.e. extending the selection
// till the end of the longest line.
helpers.doKeys('<C-v>', 'l', 'j', 'j', '6', 'l', 'd');
helpers.doKeys('d', 'd', 'd', 'd');
eq('', cm.getValue());
}, {value: '1234\n5678\nabcdefg'});
testVim('visual_block_truncate_on_short_line', function(cm, vim, helpers) {
// check for left side selection in case
// of moving up to a shorter line.
cm.replaceRange('hello world\n{\nthis is\nsparta!', cm.getCursor());
cm.replaceRange('', cm.getCursor());
cm.setCursor(3, 4);
helpers.doKeys('<C-v>', 'l', 'k', 'k', 'd');
eq('hello world\n{\ntis\nsa!', cm.getValue());
cm.replaceRange('12345\n67891\nabcde', {line: 0, ch: 0}, {line: cm.lastLine(), ch: 6});
}, {value: 'hello world\n{\nthis is\nsparta!'});
testVim('visual_block_corners', function(cm, vim, helpers) {
cm.setCursor(1, 2);
helpers.doKeys('<C-v>', '2', 'l', 'k');
// circle around the anchor
Expand All @@ -1733,10 +1825,12 @@ testVim('visual_block', function(cm, vim, helpers) {
helpers.doKeys('4', 'l');
selections = cm.getSelections();
eq('891cde', selections.join(''));
}, {value: '12345\n67891\nabcde'});
testVim('visual_block_mode_switch', function(cm, vim, helpers) {
// switch between visual modes
cm.setCursor(1, 1);
// blockwise to characterwise visual
helpers.doKeys('<C-v>', '<C-v>', 'j', 'l', 'v');
helpers.doKeys('<C-v>', 'j', 'l', 'v');
selections = cm.getSelections();
eq('7891\nabc', selections.join(''));
// characterwise to blockwise
Expand All @@ -1747,7 +1841,7 @@ testVim('visual_block', function(cm, vim, helpers) {
helpers.doKeys('V');
selections = cm.getSelections();
eq('67891\nabcde', selections.join(''));
}, {value: '1234\n5678\nabcdefg'});
}, {value: '12345\n67891\nabcde'});
testVim('visual_block_crossing_short_line', function(cm, vim, helpers) {
// visual block with long and short lines
cm.setCursor(0, 3);
Expand All @@ -1757,11 +1851,20 @@ testVim('visual_block_crossing_short_line', function(cm, vim, helpers) {
helpers.doKeys('3', 'k');
selections = cm.getSelections().join();
eq('4', selections);
}, {value: '123456\n78\nabcdefg\nfoobar'});
helpers.doKeys('5', 'j', 'k');
selections = cm.getSelections().join("");
eq(10, selections.length);
}, {value: '123456\n78\nabcdefg\nfoobar\n}\n'});
testVim('visual_block_curPos_on_exit', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('<C-v>', '3' , 'l', '<Esc>');
eqPos(makeCursor(0, 3), cm.getCursor());
helpers.doKeys('h', '<C-v>', '2' , 'j' ,'3' , 'l');
eq(cm.getSelections().join(), "3456,,cdef");
helpers.doKeys('4' , 'h');
eq(cm.getSelections().join(), "23,8,bc");
helpers.doKeys('2' , 'l');
eq(cm.getSelections().join(), "34,,cd");
}, {value: '123456\n78\nabcdefg\nfoobar'});

testVim('visual_marks', function(cm, vim, helpers) {
Expand All @@ -1776,6 +1879,7 @@ testVim('visual_marks', function(cm, vim, helpers) {
testVim('visual_join', function(cm, vim, helpers) {
helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J');
eq(' 1 2 3\n 4\n 5', cm.getValue());
is(!vim.visualMode);
}, { value: ' 1\n 2\n 3\n 4\n 5' });
testVim('visual_blank', function(cm, vim, helpers) {
helpers.doKeys('v', 'k');
Expand Down Expand Up @@ -1817,12 +1921,15 @@ testVim('reselect_visual_block', function(cm, vim, helpers) {
helpers.doKeys('<C-v>', 'k', 'h', '<C-v>');
cm.setCursor(2, 1);
helpers.doKeys('v', 'l', 'g', 'v');
helpers.assertCursorAt(0, 1);
eqPos(Pos(1, 2), vim.sel.anchor);
eqPos(Pos(0, 1), vim.sel.head);
// Ensure selection is done with visual block mode rather than one
// continuous range.
eq(cm.getSelections().join(''), '23oo')
helpers.doKeys('g', 'v');
helpers.assertCursorAt(2, 3);
eqPos(Pos(2, 1), vim.sel.anchor);
eqPos(Pos(2, 2), vim.sel.head);
helpers.doKeys('<Esc>');
// Ensure selection of deleted range
cm.setCursor(1, 1);
helpers.doKeys('v', '<C-v>', 'j', 'd', 'g', 'v');
Expand Down Expand Up @@ -1856,11 +1963,14 @@ testVim('o_visual', function(cm, vim, helpers) {
testVim('o_visual_block', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('<C-v>','3','j','l','l', 'o');
helpers.assertCursorAt(0, 1);
eqPos(Pos(3, 3), vim.sel.anchor);
eqPos(Pos(0, 1), vim.sel.head);
helpers.doKeys('O');
helpers.assertCursorAt(0, 4);
eqPos(Pos(3, 1), vim.sel.anchor);
eqPos(Pos(0, 3), vim.sel.head);
helpers.doKeys('o');
helpers.assertCursorAt(3, 1);
eqPos(Pos(0, 3), vim.sel.anchor);
eqPos(Pos(3, 1), vim.sel.head);
}, { value: 'abcd\nefgh\nijkl\nmnop'});
testVim('changeCase_visual', function(cm, vim, helpers) {
cm.setCursor(0, 0);
Expand Down Expand Up @@ -1895,7 +2005,9 @@ testVim('changeCase_visual_block', function(cm, vim, helpers) {
}, { value: 'abcdef\nghijkl\nmnopq\nfoo'});
testVim('visual_paste', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('v', 'l', 'l', 'y', 'j', 'v', 'l', 'p');
helpers.doKeys('v', 'l', 'l', 'y');
helpers.assertCursorAt(0, 0);
helpers.doKeys('3', 'l', 'j', 'v', 'l', 'p');
helpers.assertCursorAt(1, 5);
eq('this is a\nunithitest for visual paste', cm.getValue());
cm.setCursor(0, 0);
Expand Down
2 changes: 1 addition & 1 deletion theme/3024-day.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@
.cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;}

.cm-s-3024-day .CodeMirror-activeline-background {background: #e8f2ff !important;}
.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important;}
5 changes: 0 additions & 5 deletions theme/solarized.css
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
text-decoration-style: dotted;
}
.cm-s-solarized .cm-strong { color: #eee; }
.cm-s-solarized .cm-tab:before {
content: "➤"; /*visualize tab character*/
color: #586e75;
position:absolute;
}
.cm-s-solarized .cm-error,
.cm-s-solarized .cm-invalidchar {
color: #586e75;
Expand Down