90 changes: 61 additions & 29 deletions mode/xml/xml.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
var alignCDATA = parserConfig.alignCDATA;

// Return variables for tokenizers
var tagName, type, setStyle;
var type, setStyle;

function inText(stream, state) {
function chain(parser) {
Expand All @@ -85,15 +85,9 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
state.tokenize = inBlock("meta", "?>");
return "meta";
} else {
var isClose = stream.eat("/");
tagName = "";
var c;
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
if (Kludges.caseFold) tagName = tagName.toLowerCase();
if (!tagName) return "tag error";
type = isClose ? "closeTag" : "openTag";
type = stream.eat("/") ? "closeTag" : "openTag";
state.tokenize = inTag;
return "tag";
return "tag bracket";
}
} else if (ch == "&") {
var ok;
Expand All @@ -118,7 +112,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "tag";
return "tag bracket";
} else if (ch == "=") {
type = "equals";
return null;
Expand All @@ -133,7 +127,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
state.stringStartCol = stream.column();
return state.tokenize(stream, state);
} else {
stream.eatWhile(/[^\s\u00a0=<>\"\']/);
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
return "word";
}
}
Expand Down Expand Up @@ -213,24 +207,40 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {

function baseState(type, stream, state) {
if (type == "openTag") {
state.tagName = tagName;
state.tagStart = stream.column();
return attrState;
return tagNameState;
} else if (type == "closeTag") {
var err = false;
if (state.context) {
if (state.context.tagName != tagName) {
if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
popContext(state);
err = !state.context || state.context.tagName != tagName;
}
return closeTagNameState;
} else {
return baseState;
}
}
function tagNameState(type, stream, state) {
if (type == "word") {
state.tagName = stream.current();
setStyle = "tag";
return attrState;
} else {
setStyle = "error";
return tagNameState;
}
}
function closeTagNameState(type, stream, state) {
if (type == "word") {
var tagName = stream.current();
if (state.context && state.context.tagName != tagName &&
Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
popContext(state);
if (state.context && state.context.tagName == tagName) {
setStyle = "tag";
return closeState;
} else {
err = true;
setStyle = "tag error";
return closeStateErr;
}
if (err) setStyle = "error";
return err ? closeStateErr : closeState;
} else {
return baseState;
setStyle = "error";
return closeStateErr;
}
}

Expand Down Expand Up @@ -296,7 +306,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
state.indented = stream.indentation();

if (stream.eatSpace()) return null;
tagName = type = null;
type = null;
var style = state.tokenize(stream, state);
if ((style || type) && style != "comment") {
setStyle = null;
Expand All @@ -311,7 +321,10 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
var context = state.context;
// Indent multi-line strings (e.g. css).
if (state.tokenize.isInAttribute) {
return state.stringStartCol + 1;
if (state.tagStart == state.indented)
return state.stringStartCol + 1;
else
return state.indented + indentUnit;
}
if (context && context.noIndent) return CodeMirror.Pass;
if (state.tokenize != inTag && state.tokenize != inText)
Expand All @@ -324,15 +337,34 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
return state.tagStart + indentUnit * multilineTagIndentFactor;
}
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
if (context && /^<\//.test(textAfter))
context = context.prev;
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
if (tagAfter && tagAfter[1]) { // Closing tag spotted
while (context) {
if (context.tagName == tagAfter[2]) {
context = context.prev;
break;
} else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
context = context.prev;
} else {
break;
}
}
} else if (tagAfter) { // Opening tag spotted
while (context) {
var grabbers = Kludges.contextGrabbers[context.tagName];
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
context = context.prev;
else
break;
}
}
while (context && !context.startOfLine)
context = context.prev;
if (context) return context.indent + indentUnit;
else return 0;
},

electricChars: "/",
electricInput: /<\/[\s\w:]+>$/,
blockCommentStart: "<!--",
blockCommentEnd: "-->",

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.0.3",
"version":"4.1.0",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [{"type": "MIT",
Expand Down
23 changes: 23 additions & 0 deletions test/doc_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,29 @@
eq(cleared, 1);
});

testDoc("sharedMarkerCopy", "A='abcde'", function(a) {
var shared = a.markText(Pos(0, 1), Pos(0, 3), {shared: true});
var b = a.linkedDoc();
var found = b.findMarksAt(Pos(0, 2));
eq(found.length, 1);
eq(found[0], shared);
shared.clear();
eq(b.findMarksAt(Pos(0, 2)), 0);
});

testDoc("sharedMarkerDetach", "A='abcde' B<A C<B", function(a, b, c) {
var shared = a.markText(Pos(0, 1), Pos(0, 3), {shared: true});
a.unlinkDoc(b);
var inB = b.findMarksAt(Pos(0, 2));
eq(inB.length, 1);
is(inB[0] != shared);
var inC = c.findMarksAt(Pos(0, 2));
eq(inC.length, 1);
is(inC[0] != shared);
inC[0].clear();
is(shared.find());
});

testDoc("sharedBookmark", "A='ab\ncd\nef\ngh' B<A C<~A/1-2", function(a, b, c) {
var mark = b.setBookmark(Pos(1, 1), {shared: true});
var found = a.findMarksAt(Pos(1, 1));
Expand Down
6 changes: 6 additions & 0 deletions test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<script src="../addon/edit/matchbrackets.js"></script>
<script src="../addon/comment/comment.js"></script>
<script src="../mode/javascript/javascript.js"></script>
<script src="../mode/clike/clike.js"></script>
<script src="../mode/php/php.js"></script>
<script src="../mode/xml/xml.js"></script>
<script src="../keymap/vim.js"></script>
<script src="../keymap/emacs.js"></script>
Expand Down Expand Up @@ -78,11 +80,13 @@ <h2>Test Suite</h2>
<script src="search_test.js"></script>
<script src="mode_test.js"></script>
<script src="../mode/javascript/test.js"></script>
<script src="../mode/php/test.js"></script>
<script src="../mode/css/css.js"></script>
<script src="../mode/css/test.js"></script>
<script src="../mode/css/scss_test.js"></script>
<script src="../mode/css/less_test.js"></script>
<script src="../mode/xml/xml.js"></script>
<script src="../mode/xml/test.js"></script>
<script src="../mode/htmlmixed/htmlmixed.js"></script>
<script src="../mode/ruby/ruby.js"></script>
<script src="../mode/ruby/test.js"></script>
Expand All @@ -94,6 +98,8 @@ <h2>Test Suite</h2>
<script src="../mode/gfm/test.js"></script>
<script src="../mode/stex/stex.js"></script>
<script src="../mode/stex/test.js"></script>
<script src="../mode/verilog/verilog.js"></script>
<script src="../mode/verilog/test.js"></script>
<script src="../mode/xquery/xquery.js"></script>
<script src="../mode/xquery/test.js"></script>
<script src="../addon/mode/multiplex_test.js"></script>
Expand Down
2 changes: 2 additions & 0 deletions test/mode_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
/* Start copied code from CodeMirror.highlight */
while (!stream.eol()) {
var compare = mode.token(stream, state), substr = stream.current();
if (stream.start >= stream.pos)
throw new Failure("Failed to advance the stream." + stream.string + " " + stream.pos);
if (compare && compare.indexOf(" ") > -1) compare = compare.split(' ').sort().join(' ');
stream.start = stream.pos;
if (pos && st[pos-2] == compare && !newLine) {
Expand Down
27 changes: 27 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1776,6 +1776,20 @@ testCM("lineStyleFromMode", function(cm) {
is(/^\s*cm-span\s*$/.test(spanElts[0].className));
}, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: <tag> <tag>"});

testCM("lineStyleFromBlankLine", function(cm) {
CodeMirror.defineMode("lineStyleFromBlankLine_mode", function() {
return {token: function(stream) { stream.skipToEnd(); return "comment"; },
blankLine: function() { return "line-blank"; }};
});
cm.setOption("mode", "lineStyleFromBlankLine_mode");
var blankElts = byClassName(cm.getWrapperElement(), "blank");
eq(blankElts.length, 1);
eq(blankElts[0].nodeName, "PRE");
cm.replaceRange("x", Pos(1, 0));
blankElts = byClassName(cm.getWrapperElement(), "blank");
eq(blankElts.length, 0);
}, {value: "foo\n\nbar"});

CodeMirror.registerHelper("xxx", "a", "A");
CodeMirror.registerHelper("xxx", "b", "B");
CodeMirror.defineMode("yyy", function() {
Expand Down Expand Up @@ -1876,3 +1890,16 @@ testCM("alwaysMergeSelEventWithChangeOrigin", function(cm) {
cm.undoSelection();
eq(cm.getValue(), "Va");
}, {value: "a"});

testCM("getTokenTypeAt", function(cm) {
eq(cm.getTokenTypeAt(Pos(0, 0)), "number");
eq(cm.getTokenTypeAt(Pos(0, 6)), "string");
cm.addOverlay({
token: function(stream) {
if (stream.match("foo")) return "foo";
else stream.next();
}
});
eq(byClassName(cm.getWrapperElement(), "cm-foo").length, 1);
eq(cm.getTokenTypeAt(Pos(0, 6)), "string");
}, {value: "1 + 'foo'", mode: "javascript"});
193 changes: 186 additions & 7 deletions test/vim_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ testJumplist('jumplist_gg', ['g', 'g', '<C-o>'], [5,2], [5,2]);
testJumplist('jumplist_%', ['%', '<C-o>'], [1,5], [1,5]);
testJumplist('jumplist_{', ['{', '<C-o>'], [1,5], [1,5]);
testJumplist('jumplist_}', ['}', '<C-o>'], [1,5], [1,5]);
testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', '<C-i>'], [1,5], [1,5]);
testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', '<C-i>'], [1,0], [1,5]);
testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', '<C-i>'], [1,5], [1,5]);
testJumplist('jumplist_*_cachedCursor', ['*', '<C-o>'], [1,3], [1,3]);
testJumplist('jumplist_#_cachedCursor', ['#', '<C-o>'], [1,3], [1,3]);
Expand Down Expand Up @@ -1015,6 +1015,7 @@ testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo');
// Open and close on same line
testEdit('di(_open_spc', 'foo (bAr) baz', /\(/, 'di(', 'foo () baz');
testEdit('di)_open_spc', 'foo (bAr) baz', /\(/, 'di)', 'foo () baz');
testEdit('dib_open_spc', 'foo (bAr) baz', /\(/, 'dib', 'foo () baz');
testEdit('da(_open_spc', 'foo (bAr) baz', /\(/, 'da(', 'foo baz');
testEdit('da)_open_spc', 'foo (bAr) baz', /\(/, 'da)', 'foo baz');

Expand All @@ -1028,11 +1029,26 @@ testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz');
testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo baz');
testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo baz');

// delete around and inner b.
testEdit('dab_on_(_should_delete_around_()block', 'o( in(abc) )', /\(a/, 'dab', 'o( in )');

// delete around and inner B.
testEdit('daB_on_{_should_delete_around_{}block', 'o{ in{abc} }', /{a/, 'daB', 'o{ in }');
testEdit('diB_on_{_should_delete_inner_{}block', 'o{ in{abc} }', /{a/, 'diB', 'o{ in{} }');

testEdit('da{_on_{_should_delete_inner_block', 'o{ in{abc} }', /{a/, 'da{', 'o{ in }');
testEdit('di[_on_(_should_not_delete', 'foo (bAr) baz', /\(/, 'di[', 'foo (bAr) baz');
testEdit('di[_on_)_should_not_delete', 'foo (bAr) baz', /\)/, 'di[', 'foo (bAr) baz');
testEdit('da[_on_(_should_not_delete', 'foo (bAr) baz', /\(/, 'da[', 'foo (bAr) baz');
testEdit('da[_on_)_should_not_delete', 'foo (bAr) baz', /\)/, 'da[', 'foo (bAr) baz');
testMotion('di(_outside_should_stay', ['d', 'i', '('], { line: 0, ch: 0}, { line: 0, ch: 0});

// Open and close on different lines, equally indented
testEdit('di{_middle_spc', 'a{\n\tbar\n}b', /r/, 'di{', 'a{}b');
testEdit('di}_middle_spc', 'a{\n\tbar\n}b', /r/, 'di}', 'a{}b');
testEdit('da{_middle_spc', 'a{\n\tbar\n}b', /r/, 'da{', 'ab');
testEdit('da}_middle_spc', 'a{\n\tbar\n}b', /r/, 'da}', 'ab');
testEdit('daB_middle_spc', 'a{\n\tbar\n}b', /r/, 'daB', 'ab');

// open and close on diff lines, open indented less than close
testEdit('di{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di{', 'a{}b');
Expand Down Expand Up @@ -1236,6 +1252,31 @@ testVim('p_lastline', function(cm, vim, helpers) {
eq('___\n a\nd\n a\nd', cm.getValue());
helpers.assertCursorAt(1, 2);
}, { value: '___' });
testVim(']p_first_indent_is_smaller', function(cm, vim, helpers) {
helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
helpers.doKeys(']', 'p');
eq(' ___\n abc\n def', cm.getValue());
}, { value: ' ___' });
testVim(']p_first_indent_is_larger', function(cm, vim, helpers) {
helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
helpers.doKeys(']', 'p');
eq(' ___\n abc\ndef', cm.getValue());
}, { value: ' ___' });
testVim(']p_with_tab_indents', function(cm, vim, helpers) {
helpers.getRegisterController().pushText('"', 'yank', '\t\tabc\n\t\t\tdef\n', true);
helpers.doKeys(']', 'p');
eq('\t___\n\tabc\n\t\tdef', cm.getValue());
}, { value: '\t___', indentWithTabs: true});
testVim(']p_with_spaces_translated_to_tabs', function(cm, vim, helpers) {
helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
helpers.doKeys(']', 'p');
eq('\t___\n\tabc\n\t\tdef', cm.getValue());
}, { value: '\t___', indentWithTabs: true, tabSize: 2 });
testVim('[p', function(cm, vim, helpers) {
helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true);
helpers.doKeys('[', 'p');
eq(' abc\n def\n ___', cm.getValue());
}, { value: ' ___' });
testVim('P', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
Expand Down Expand Up @@ -1270,11 +1311,13 @@ testVim('mark', function(cm, vim, helpers) {
cm.setCursor(2, 2);
helpers.doKeys('m', 't');
cm.setCursor(0, 0);
helpers.doKeys('\'', 't');
helpers.assertCursorAt(2, 2);
cm.setCursor(0, 0);
helpers.doKeys('`', 't');
helpers.assertCursorAt(2, 2);
cm.setCursor(2, 0);
cm.replaceRange(' h', cm.getCursor());
cm.setCursor(0, 0);
helpers.doKeys('\'', 't');
helpers.assertCursorAt(2, 3);
});
testVim('jumpToMark_next', function(cm, vim, helpers) {
cm.setCursor(2, 2);
Expand Down Expand Up @@ -1524,13 +1567,13 @@ testVim('visual_line', function(cm, vim, helpers) {
eq(' 4\n 5', cm.getValue());
}, { value: ' 1\n 2\n 3\n 4\n 5' });
testVim('visual_marks', function(cm, vim, helpers) {
helpers.doKeys('l', 'v', 'l', 'l', 'v');
helpers.doKeys('l', 'v', 'l', 'l', 'j', 'j', 'v');
// Test visual mode marks
cm.setCursor(0, 0);
cm.setCursor(2, 1);
helpers.doKeys('\'', '<');
helpers.assertCursorAt(0, 1);
helpers.doKeys('\'', '>');
helpers.assertCursorAt(0, 3);
helpers.assertCursorAt(2, 0);
});
testVim('visual_join', function(cm, vim, helpers) {
helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J');
Expand Down Expand Up @@ -1750,6 +1793,22 @@ testVim('#', function(cm, vim, helpers) {
helpers.doKeys('#');
helpers.assertCursorAt(1, 8);
}, { value: ' := match nomatch match \nnomatch Match' });
testVim('g*', function(cm, vim, helpers) {
cm.setCursor(0, 8);
helpers.doKeys('g', '*');
helpers.assertCursorAt(0, 18);
cm.setCursor(0, 8);
helpers.doKeys('3', 'g', '*');
helpers.assertCursorAt(1, 8);
}, { value: 'matches match alsoMatch\nmatchme matching' });
testVim('g#', function(cm, vim, helpers) {
cm.setCursor(0, 8);
helpers.doKeys('g', '#');
helpers.assertCursorAt(0, 0);
cm.setCursor(0, 8);
helpers.doKeys('3', 'g', '#');
helpers.assertCursorAt(1, 0);
}, { value: 'matches match alsoMatch\nmatchme matching' });
testVim('macro_insert', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'a', '0', 'i');
Expand All @@ -1769,6 +1828,46 @@ testVim('macro_space', function(cm, vim, helpers) {
helpers.doKeys('@', 'a');
helpers.assertCursorAt(0, 8);
}, { value: 'one line of text.'});
testVim('macro_t_search', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'a', 't', 'e', 'q');
helpers.assertCursorAt(0, 1);
helpers.doKeys('l', '@', 'a');
helpers.assertCursorAt(0, 6);
helpers.doKeys('l', ';');
helpers.assertCursorAt(0, 12);
}, { value: 'one line of text.'});
testVim('macro_f_search', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'b', 'f', 'e', 'q');
helpers.assertCursorAt(0, 2);
helpers.doKeys('@', 'b');
helpers.assertCursorAt(0, 7);
helpers.doKeys(';');
helpers.assertCursorAt(0, 13);
}, { value: 'one line of text.'});
testVim('macro_slash_search', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'c');
cm.openDialog = helpers.fakeOpenDialog('e');
helpers.doKeys('/', 'q');
helpers.assertCursorAt(0, 2);
helpers.doKeys('@', 'c');
helpers.assertCursorAt(0, 7);
helpers.doKeys('n');
helpers.assertCursorAt(0, 13);
}, { value: 'one line of text.'});
testVim('macro_multislash_search', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'd');
cm.openDialog = helpers.fakeOpenDialog('e');
helpers.doKeys('/');
cm.openDialog = helpers.fakeOpenDialog('t');
helpers.doKeys('/', 'q');
helpers.assertCursorAt(0, 12);
helpers.doKeys('@', 'd');
helpers.assertCursorAt(0, 15);
}, { value: 'one line of text to rule them all.'});
testVim('macro_parens', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'z', 'i');
Expand Down Expand Up @@ -1827,6 +1926,50 @@ testVim('yank_register', function(cm, vim, helpers) {
});
helpers.doKeys(':');
}, { value: 'foo\nbar'});
testVim('yank_append_line_to_line_register', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('"', 'a', 'y', 'y');
helpers.doKeys('j', '"', 'A', 'y', 'y');
cm.openDialog = helpers.fakeOpenDialog('registers');
cm.openNotification = helpers.fakeOpenNotification(function(text) {
is(/a\s+foo\nbar/.test(text));
is(/"\s+foo\nbar/.test(text));
});
helpers.doKeys(':');
}, { value: 'foo\nbar'});
testVim('yank_append_word_to_word_register', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('"', 'a', 'y', 'w');
helpers.doKeys('j', '"', 'A', 'y', 'w');
cm.openDialog = helpers.fakeOpenDialog('registers');
cm.openNotification = helpers.fakeOpenNotification(function(text) {
is(/a\s+foobar/.test(text));
is(/"\s+foobar/.test(text));
});
helpers.doKeys(':');
}, { value: 'foo\nbar'});
testVim('yank_append_line_to_word_register', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('"', 'a', 'y', 'w');
helpers.doKeys('j', '"', 'A', 'y', 'y');
cm.openDialog = helpers.fakeOpenDialog('registers');
cm.openNotification = helpers.fakeOpenNotification(function(text) {
is(/a\s+foo\nbar/.test(text));
is(/"\s+foo\nbar/.test(text));
});
helpers.doKeys(':');
}, { value: 'foo\nbar'});
testVim('yank_append_word_to_line_register', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('"', 'a', 'y', 'y');
helpers.doKeys('j', '"', 'A', 'y', 'w');
cm.openDialog = helpers.fakeOpenDialog('registers');
cm.openNotification = helpers.fakeOpenNotification(function(text) {
is(/a\s+foo\nbar/.test(text));
is(/"\s+foo\nbar/.test(text));
});
helpers.doKeys(':');
}, { value: 'foo\nbar'});
testVim('macro_register', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('q', 'a', 'i');
Expand All @@ -1844,6 +1987,25 @@ testVim('macro_register', function(cm, vim, helpers) {
});
helpers.doKeys(':');
}, { value: ''});
testVim('._register', function(cm,vim,helpers) {
cm.setCursor(0,0);
helpers.doKeys('i');
cm.replaceRange('foo',cm.getCursor());
helpers.doInsertModeKeys('Esc');
cm.openDialog = helpers.fakeOpenDialog('registers');
cm.openNotification = helpers.fakeOpenNotification(function(text) {
is(/\.\s+foo/.test(text));
});
helpers.doKeys(':');
}, {value: ''});
testVim(':_register', function(cm,vim,helpers) {
helpers.doEx('bar');
cm.openDialog = helpers.fakeOpenDialog('registers');
cm.openNotification = helpers.fakeOpenNotification(function(text) {
is(/:\s+bar/.test(text));
});
helpers.doKeys(':');
}, {value: ''});
testVim('.', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('2', 'd', 'w');
Expand Down Expand Up @@ -1947,6 +2109,14 @@ testVim('._delete_repeat', function(cm, vim, helpers) {
eq('zzce', cm.getValue());
helpers.assertCursorAt(0, 1);
}, { value: 'zzabcde'});
testVim('._visual_>', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('V', 'j', '>');
cm.setCursor(2, 0)
helpers.doKeys('.');
eq(' 1\n 2\n 3\n 4', cm.getValue());
helpers.assertCursorAt(2, 2);
}, { value: '1\n2\n3\n4'});
testVim('f;', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('f', 'x');
Expand Down Expand Up @@ -2496,6 +2666,13 @@ testVim('ex_substitute_javascript', function(cm, vim, helpers) {
helpers.doEx('s/\\(\\d+\\)/$$ $\' $` $& \\1/')
eq('a $$ $\' $` $& 0 b', cm.getValue());
}, { value: 'a 0 b' });
testVim('ex_substitute_empty_arguments', function(cm,vim,helpers) {
cm.setCursor(0, 0);
helpers.doEx('s/a/b');
cm.setCursor(1, 0);
helpers.doEx('s');
eq('b b\nb b', cm.getValue());
}, {value: 'a a\na a'});

// More complex substitute tests that test both pcre and nopcre options.
function testSubstitute(name, options) {
Expand Down Expand Up @@ -2857,3 +3034,5 @@ testVim('beforeSelectionChange', function(cm, vim, helpers) {
cm.setCursor(0, 100);
eqPos(cm.getCursor('head'), cm.getCursor('anchor'));
}, { value: 'abc' });


1 change: 0 additions & 1 deletion theme/ambiance.css
4 changes: 0 additions & 4 deletions theme/lesser-dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ Ported to CodeMirror by Peter Kroon
.cm-s-lesser-dark {
line-height: 1.3em;
}
.cm-s-lesser-dark {
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Monaco', Courier, monospace !important;
}

.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }
.cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/
.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
Expand Down
2 changes: 1 addition & 1 deletion theme/mdn-like.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation
*/
.cm-s-mdn-like.CodeMirror { color: #999; font-family: monospace; background-color: #fff; }
.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; }
.cm-s-mdn-like .CodeMirror-selected { background: #cfc !important; }

.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; }
Expand Down
1 change: 0 additions & 1 deletion theme/pastel-on-dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
background: #2c2827;
color: #8F938F;
line-height: 1.5;
font-family: consolas, Courier, monospace;
font-size: 14px;
}
.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; }
Expand Down
2 changes: 0 additions & 2 deletions theme/rubyblue.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
.cm-s-rubyblue { font-family: Trebuchet, Verdana, sans-serif; } /* - customized editor font - */

.cm-s-rubyblue.CodeMirror { background: #112435; color: white; }
.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }
.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }
Expand Down
20 changes: 3 additions & 17 deletions theme/solarized.css

Large diffs are not rendered by default.