From f175e8d455717416cf3c1a54c831896bb37ef78c Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke MIME type defined: MIME type defined: { } CodeMi
+
diff --git a/index.html b/index.html
index 6d074dd334..54f0287ff6 100644
--- a/index.html
+++ b/index.html
@@ -46,6 +46,7 @@
Supported modes:
CodeMirror: INI mode
+
+
+
+ text/ini.{ } CodeMi
-
diff --git a/index.html b/index.html
index 54f0287ff6..6d074dd334 100644
--- a/index.html
+++ b/index.html
@@ -46,7 +46,6 @@
Supported modes:
CodeMirror: INI mode
-
-
-
- text/ini.Configuration
onHighlightComplete (function)onUpdate (function)Writing CodeMirror Modes
which is given a state and should return a safe copy of that
state.
By default, CodeMirror will stop re-parsing
- a document as soon as it encounters a few lines that were
- highlighted the same in the old parse as in the new one. It is
- possible to provide an explicit way to test whether a state is
- equivalent to another one, which CodeMirror will use (instead of
- the unchanged-lines heuristic) to decide when to stop
- highlighting. You do this by providing
- a compareStates method on your mode object, which
- takes two state arguments and returns a boolean indicating whether
- they are equivalent. See the XML mode, which uses this to provide
- reliable highlighting of bad closing tags, as an example.
If you want your mode to provide smart indentation
(though the Finally, the The The indentLine
method and the indentAuto
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 624f71b19e..68694effd1 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -64,9 +64,9 @@ window.CodeMirror = (function() {
var poll = new Delayed(), highlight = new Delayed(), blinker;
// mode holds a mode API object. doc is the tree of Line objects,
- // work an array of lines that should be parsed, and history the
- // undo history (instance of History constructor).
- var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused;
+ // frontier is the point up to which the content has been parsed,
+ // and history the undo history (instance of History constructor).
+ var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), frontier = 0, focused;
loadMode();
// The selection. These are always maintained to point at valid
// positions. Inverted is used to remember that the user is
@@ -363,6 +363,8 @@ window.CodeMirror = (function() {
}
function lineContent(line, wrapAt) {
+ if (!line.styles)
+ line.highlight(mode, line.stateAfter = getStateBefore(lineNo(line)), options.tabSize);
return line.getContent(options.tabSize, wrapAt, options.lineWrapping);
}
@@ -795,19 +797,11 @@ window.CodeMirror = (function() {
if (recomputeMaxLength) updateMaxLine = true;
}
- // Add these lines to the work array, so that they will be
- // highlighted. Adjust work lines if lines were added/removed.
- var newWork = [], lendiff = newText.length - nlines - 1;
- for (var i = 0, l = work.length; i < l; ++i) {
- var task = work[i];
- if (task < from.line) newWork.push(task);
- else if (task > to.line) newWork.push(task + lendiff);
- }
- var hlEnd = from.line + Math.min(newText.length, 500);
- highlightLines(from.line, hlEnd);
- newWork.push(hlEnd);
- work = newWork;
- startWorker(100);
+ // Adjust frontier, schedule worker
+ frontier = Math.min(frontier, from.line);
+ startWorker(400);
+
+ var lendiff = newText.length - nlines - 1;
// Remember that these lines changed, for updating the display
changes.push({from: from.line, to: to.line + 1, diff: lendiff});
var changeObj = {from: from, to: to, text: newText};
@@ -1076,6 +1070,7 @@ window.CodeMirror = (function() {
});
showingFrom = from; showingTo = to;
displayOffset = heightAtLine(doc, from);
+ startWorker(100);
// Since this is all rather error prone, it is honoured with the
// only assertion in the whole file.
@@ -1455,8 +1450,8 @@ window.CodeMirror = (function() {
function loadMode() {
mode = CodeMirror.getMode(options, options.mode);
doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
- work = [0];
- startWorker();
+ frontier = 0;
+ startWorker(100);
}
function gutterChanged() {
var visible = options.gutter || options.lineNumbers;
@@ -1867,70 +1862,39 @@ window.CodeMirror = (function() {
return minline;
}
function getStateBefore(n) {
- var start = findStartLine(n), state = start && getLine(start-1).stateAfter;
+ var pos = findStartLine(n), state = pos && getLine(pos-1).stateAfter;
if (!state) state = startState(mode);
else state = copyState(mode, state);
- doc.iter(start, n, function(line) {
- line.highlight(mode, state, options.tabSize);
- line.stateAfter = copyState(mode, state);
+ doc.iter(pos, n, function(line) {
+ line.process(mode, state, options.tabSize);
+ line.stateAfter = (pos == n - 1 || pos % 5 == 0) ? copyState(mode, state) : null;
});
- if (start < n) changes.push({from: start, to: n});
- if (n < doc.size && !getLine(n).stateAfter) work.push(n);
return state;
}
- function highlightLines(start, end) {
- var state = getStateBefore(start);
- doc.iter(start, end, function(line) {
- line.highlight(mode, state, options.tabSize);
- line.stateAfter = copyState(mode, state);
- });
- }
function highlightWorker() {
- var end = +new Date + options.workTime;
- var foundWork = work.length;
- while (work.length) {
- if (!getLine(showingFrom).stateAfter) var task = showingFrom;
- else var task = work.pop();
- if (task >= doc.size) continue;
- var start = findStartLine(task), state = start && getLine(start-1).stateAfter;
- if (state) state = copyState(mode, state);
- else state = startState(mode);
-
- var unchanged = 0, compare = mode.compareStates, realChange = false,
- i = start, bail = false;
- doc.iter(i, doc.size, function(line) {
- var hadState = line.stateAfter;
- if (+new Date > end) {
- work.push(i);
- startWorker(options.workDelay);
- if (realChange) changes.push({from: task, to: i + 1});
- return (bail = true);
- }
- var changed = line.highlight(mode, state, options.tabSize);
- if (changed) realChange = true;
+ if (frontier >= showingTo) return;
+ var end = +new Date + options.workTime, state = copyState(mode, getStateBefore(frontier));
+ var startFrontier = frontier;
+ doc.iter(frontier, showingTo, function(line) {
+ if (frontier >= showingFrom) { // Visible
+ line.highlight(mode, state, options.tabSize);
line.stateAfter = copyState(mode, state);
- var done = null;
- if (compare) {
- var same = hadState && compare(hadState, state);
- if (same != Pass) done = !!same;
- }
- if (done == null) {
- if (changed !== false || !hadState) unchanged = 0;
- else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
- done = true;
- }
- if (done) return true;
- ++i;
- });
- if (bail) return;
- if (realChange) changes.push({from: task, to: i + 1});
- }
- if (foundWork && options.onHighlightComplete)
- options.onHighlightComplete(instance);
+ } else {
+ line.process(mode, state, options.tabSize);
+ line.stateAfter = frontier % 5 == 0 ? copyState(mode, state) : null;
+ }
+ ++frontier;
+ if (+new Date > end) {
+ startWorker(options.workDelay);
+ return true;
+ }
+ });
+ if (showingTo > startFrontier && frontier >= showingFrom)
+ operation(function() {changes.push({from: startFrontier, to: frontier});})();
}
function startWorker(time) {
- if (!work.length) return;
- highlight.set(time, operation(highlightWorker));
+ if (frontier < showingTo)
+ highlight.set(time, highlightWorker);
}
// Operations are used to wrap changes in such a way that each
@@ -2029,7 +1993,6 @@ window.CodeMirror = (function() {
onCursorActivity: null,
onViewportChange: null,
onGutterClick: null,
- onHighlightComplete: null,
onUpdate: null,
onFocus: null, onBlur: null, onScroll: null,
matchBrackets: false,
@@ -2427,8 +2390,7 @@ window.CodeMirror = (function() {
// Line objects. These hold state related to a line, including
// highlighting info (the styles array).
- function Line(text, styles) {
- this.styles = styles || [text, null];
+ function Line(text) {
this.text = text;
this.height = 1;
}
@@ -2445,15 +2407,11 @@ window.CodeMirror = (function() {
return ln;
};
Line.prototype = {
- // Replace a piece of a line, keeping the styles around it intact.
+ // Replace a piece of a line, keeping the markers intact.
replace: function(from, to_, text) {
- var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_;
- copyStyles(0, from, this.styles, st);
- if (text) st.push(text, null);
- copyStyles(to, this.text.length, this.styles, st);
- this.styles = st;
+ var mk = this.marked, to = to_ == null ? this.text.length : to_;
this.text = this.text.slice(0, from) + text + this.text.slice(to);
- this.stateAfter = null;
+ this.stateAfter = this.styles = null;
if (mk) {
var diff = text.length - (to - from);
for (var i = 0; i < mk.length; ++i) {
@@ -2463,11 +2421,10 @@ window.CodeMirror = (function() {
}
}
},
- // Split a part off a line, keeping styles and markers intact.
+ // Split a part off a line, keeping markers intact.
split: function(pos, textBefore) {
- var st = [textBefore, null], mk = this.marked;
- copyStyles(pos, this.text.length, this.styles, st);
- var taken = new Line(textBefore + this.text.slice(pos), st);
+ var mk = this.marked;
+ var taken = new Line(textBefore + this.text.slice(pos));
if (mk) {
for (var i = 0; i < mk.length; ++i) {
var mark = mk[i];
@@ -2484,7 +2441,7 @@ window.CodeMirror = (function() {
append: function(line) {
var mylen = this.text.length, mk = line.marked, mymk = this.marked;
this.text += line.text;
- copyStyles(0, line.text.length, line.styles, this.styles);
+ this.styles = this.stateAfter = null;
if (mymk) {
for (var i = 0; i < mymk.length; ++i)
if (mymk[i].to == null) mymk[i].to = mylen;
@@ -2550,19 +2507,16 @@ window.CodeMirror = (function() {
// array, which contains alternating fragments of text and CSS
// classes.
highlight: function(mode, state, tabSize) {
- var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0;
- var changed = false, curWord = st[0], prevWord;
+ var stream = new StringStream(this.text, tabSize), st = this.styles || (this.styles = []);
+ var pos = st.length = 0;
if (this.text == "" && mode.blankLine) mode.blankLine(state);
while (!stream.eol()) {
- var style = mode.token(stream, state);
- var substr = this.text.slice(stream.start, stream.pos);
+ var style = mode.token(stream, state), substr = stream.current();
stream.start = stream.pos;
- if (pos && st[pos-1] == style)
+ if (pos && st[pos-1] == style) {
st[pos-2] += substr;
- else if (substr) {
- if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true;
+ } else if (substr) {
st[pos++] = substr; st[pos++] = style;
- prevWord = curWord; curWord = st[pos];
}
// Give up when line is ridiculously long
if (stream.pos > 5000) {
@@ -2570,12 +2524,14 @@ window.CodeMirror = (function() {
break;
}
}
- if (st.length != pos) {st.length = pos; changed = true;}
- if (pos && st[pos-2] != prevWord) changed = true;
- // Short lines with simple highlights return null, and are
- // counted as changed by the driver because they are likely to
- // highlight the same way in various contexts.
- return changed || (st.length < 5 && this.text.length < 10 ? null : false);
+ },
+ process: function(mode, state, tabSize) {
+ var stream = new StringStream(this.text, tabSize);
+ if (this.text == "" && mode.blankLine) mode.blankLine(state);
+ while (!stream.eol() && stream.pos <= 5000) {
+ mode.token(stream, state);
+ stream.start = stream.pos;
+ }
},
// Fetch the parser token for a given character. Useful for hacks
// that want to inspect the mode state (say, for completion).
diff --git a/lib/util/multiplex.js b/lib/util/multiplex.js
index 755588b9c4..b7c1838f62 100644
--- a/lib/util/multiplex.js
+++ b/lib/util/multiplex.js
@@ -68,14 +68,6 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
},
- compareStates: function(a, b) {
- if (a.innerActive != b.innerActive) return false;
- var mode = a.innerActive || outer;
- if (!mode.compareStates) return CodeMirror.Pass;
- return mode.compareStates(a.innerActive ? a.inner : a.outer,
- b.innerActive ? b.inner : b.outer);
- },
-
electricChars: outer.electricChars
};
};
diff --git a/mode/haxe/haxe.js b/mode/haxe/haxe.js
index ea8bd834e6..64f4eb3ff8 100644
--- a/mode/haxe/haxe.js
+++ b/mode/haxe/haxe.js
@@ -421,9 +421,6 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
- compareStates: function(state1, state2) {
- return (state1.localVars == state2.localVars) && (state1.context == state2.context);
- },
electricChars: "{}"
};
diff --git a/mode/htmlmixed/htmlmixed.js b/mode/htmlmixed/htmlmixed.js
index 260a6d0dfb..5f2fc238c9 100644
--- a/mode/htmlmixed/htmlmixed.js
+++ b/mode/htmlmixed/htmlmixed.js
@@ -76,12 +76,6 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
return cssMode.indent(state.localState, textAfter);
},
- compareStates: function(a, b) {
- if (a.mode != b.mode) return false;
- if (a.localState) return CodeMirror.Pass;
- return htmlMode.compareStates(a.htmlState, b.htmlState);
- },
-
electricChars: "/{}:"
};
}, "xml", "javascript", "css");
diff --git a/mode/tiki/tiki.js b/mode/tiki/tiki.js
index 24bf0fbfe5..af83dc1b5b 100644
--- a/mode/tiki/tiki.js
+++ b/mode/tiki/tiki.js
@@ -301,13 +301,6 @@ CodeMirror.defineMode('tiki', function(config, parserConfig) {
if (context) return context.indent + indentUnit;
else return 0;
},
- compareStates: function(a, b) {
- if (a.indented != b.indented || a.pluginName != b.pluginName) return false;
- for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
- if (!ca || !cb) return ca == cb;
- if (ca.pluginName != cb.pluginName) return false;
- }
- },
electricChars: "/"
};
});
diff --git a/mode/xml/xml.js b/mode/xml/xml.js
index cd69f62fd5..860e368f5b 100644
--- a/mode/xml/xml.js
+++ b/mode/xml/xml.js
@@ -308,14 +308,6 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
else return 0;
},
- compareStates: function(a, b) {
- if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
- for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
- if (!ca || !cb) return ca == cb;
- if (ca.tagName != cb.tagName || ca.indent != cb.indent) return false;
- }
- },
-
electricChars: "/"
};
});
From ee16009813062592104ef07fefdc55c9c4f13342 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke Tests for the Markdown Mode
+ Basics
+
+
+ Code
+
+
+ Headers
+
+
+ Blockquotes
+
+
+ Horizontal rules
+
+
+ Links
+
+
+ Emphasis
+
+
+ Escaping
+
+
+ Summary
+
+
+
+
+
From 59d6bbef9fff62ae57276deab7f6940b39896434 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke Programming API
contextual information for a line.
- CodeMirror object
- itself has a method fromTextArea. This takes a
+ CodeMirror object itself provides
+ several useful properties. Firstly, its version
+ property contains a string that indicates the version of the
+ library. For releases, this simply
+ contains "major.minor" (for
+ example "2.33". For beta versions, " B"
+ (space, capital B) is added at the end of the string, for
+ development snapshots, " +" (space, plus) is
+ added.CodeMirror.fromTextArea
+ method provides another way to initialize an editor. It takes a
textarea DOM node as first argument and an optional configuration
object as second. It will replace the textarea with a CodeMirror
instance, and wire up the form of that textarea (if any) to make
sure the editor contents are put into the textarea when the form
- is submitted. A CodeMirror instance created this way has two
+ is submitted. A CodeMirror instance created this way has three
additional methods:
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 8eae1226e6..8c2641b5d7 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -3069,7 +3069,6 @@ window.CodeMirror = (function() {
e.appendChild(document.createTextNode(str));
} else e.textContent = str;
}
- CodeMirror.setTextContent = setTextContent;
// Used to position the cursor after an undo/redo by finding the
// last edited character.
@@ -3144,5 +3143,91 @@ window.CodeMirror = (function() {
for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
})();
+<<<<<<< HEAD
+=======
+ function iterateBidiSections(order, from, to, f) {
+ if (!order) return f(from, to, "ltr");
+ for (var i = 0; i < order.length; ++i) {
+ var part = order[i];
+ if (part.from < to && part.to > from)
+ f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
+ }
+ }
+
+ function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
+ function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
+
+ function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
+ function lineRight(line) {
+ var order = getOrder(line);
+ if (!order) return line.text.length;
+ var last = order[order.length-1];
+ return order[0].level != last.level ? line.text.length : bidiRight(last);
+ }
+ function lineStart(line) {
+ var order = getOrder(line);
+ if (!order) return 0;
+ return order[0].level % 2 ? lineRight(line) : lineLeft(line);
+ }
+ function lineEnd(line) {
+ var order = getOrder(line);
+ if (!order) return line.text.length;
+ return order[0].level % 2 ? lineLeft(line) : lineRight(line);
+ }
+
+ var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F]/;
+
+ // This is somewhat involved. It is needed in order to move
+ // 'visually' through bi-directional text -- i.e., pressing left
+ // should make the cursor go left, even when in RTL text. The
+ // tricky part is the 'jumps', where RTL and LTR text touch each
+ // other. This often requires the cursor offset to move more than
+ // one unit, in order to visually move one unit.
+ function moveVisually(line, start, dir, byUnit) {
+ var bidi = getOrder(line);
+ if (!bidi) return moveLogically(line, start, dir, byUnit);
+ var moveOneUnit = byUnit ? function(pos, dir) {
+ do pos += dir;
+ while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
+ return pos;
+ } : function(pos, dir) { return pos + dir; };
+ var linedir = bidi[0].level, last = bidi[bidi.length-1];
+ if (linedir == last.level % 2) last = null;
+ for (var i = 0; i < bidi.length; ++i) {
+ var part = bidi[i], sticky = part.level % 2 == linedir;
+ if ((part.from < start && part.to > start) ||
+ (sticky && (part.from == start || part.to == start))) break;
+ }
+ var target = moveOneUnit(start, part.level % 2 ? -dir : dir);
+ if (i == bidi.length) {
+ if (dir > 0) return null; // Moving right from EOL
+ target = last.level % 1 ? moveOneUnit(last.from, 1) : moveOneUnit(last.to, -1);
+ if (moveOneUnit(last.from, 1) == last.to) return bidiRight(bidi[i-2]);
+ else return target;
+ }
+
+ while (target != null) {
+ if (part.level % 2 == linedir) {
+ if (target < part.from || target > part.to) {
+ part = bidi[i += dir];
+ target = part && (dir > 0 == part.level % 2 ? moveOneUnit(part.to, -1) : moveOneUnit(part.from, 1));
+ } else break;
+ } else {
+ if (target == bidiLeft(part)) {
+ part = bidi[--i];
+ target = part && bidiRight(part);
+ } else if (target == bidiRight(part)) {
+ if (part == last) return line.text.length;
+ part = bidi[++i];
+ target = part && bidiLeft(part);
+ } else break;
+ }
+ }
+
+ return target < 0 || target > line.text.length ? null : target;
+ }
+
+ CodeMirror.version = "2.33 +";
+
return CodeMirror;
})();
From 79fa0bdbca40d9b275e3a805e9c3d0a033169a6d Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke
Code
'comment', '`bar`');
// Unclosed backticks
- // This should *not* be fixed by only adding the style to closed groups.
- // Instead, autocomplete should be added (see issue #344).
+ // Instead of simply marking as CODE, it would be nice to have an
+ // incomplete flag for CODE, that is styled slightly different.
MT.test('foo `bar',
- null, 'foo `bar');
+ null, 'foo ',
+ 'comment', '`bar');
// Per documentation: "To include a literal backtick character within a
// code span, you can use multiple backticks as the opening and closing
// delimiters"
MT.test('``foo ` bar``',
'comment', '``foo ` bar``');
+
+ // Tests based on Dingus
+ // http://daringfireball.net/projects/markdown/dingus
+ //
+ // Multiple backticks within an inline code block
+ MT.test('`foo```bar`',
+ 'comment', '`foo```bar`');
+ // Multiple backticks within an inline code block with a second code block
+ MT.test('`foo```bar` hello `world`',
+ 'comment', '`foo```bar`',
+ null, ' hello ',
+ 'comment', '`world`');
+ // Unclosed with several different groups of backticks
+ MT.test('``foo ``` bar` hello',
+ 'comment', '``foo ``` bar` hello');
+ // Closed with several different groups of backticks
+ MT.test('``foo ``` bar` hello`` world',
+ 'comment', '``foo ``` bar` hello``',
+ null, ' world');
Headers
@@ -86,22 +106,25 @@ Headers
// Setext headers - H1, H2
// Per documentation, "Any number of underlining =’s or -’s will work."
// http://daringfireball.net/projects/markdown/syntax#header
+ // Ideally, the text would be marked as `header` as well, but this is
+ // not really feasible at the moment. So, instead, we're testing against
+ // what works today, to avoid any regressions.
//
// Check if single underlining = works
MT.test('foo\n=',
- 'header', 'foo',
+ null, 'foo',
'header', '=');
// Check if 3+ ='s work
MT.test('foo\n===',
- 'header', 'foo',
+ null, 'foo',
'header', '===');
// Check if single underlining - works
MT.test('foo\n-',
- 'header', 'foo',
+ null, 'foo',
'header', '-');
// Check if 3+ -'s work
MT.test('foo\n---',
- 'header', 'foo',
+ null, 'foo',
'header', '---');
@@ -193,6 +216,9 @@ Links
null, ' ',
'string', '[bar]',
null, ' hello');
+ // Should only allow a single space ("...use *a* space...")
+ MT.test('[foo] [bar] hello',
+ null, '[foo] [bar] hello');
// Reference-style links with implicit link name
MT.test('[foo][] hello',
@@ -208,46 +234,61 @@ Links
// No title
MT.test('[foo]: http://example.com/',
'link', '[foo]:',
- 'string', ' http://example.com/');
- // Space in ID
+ null, ' ',
+ 'string', 'http://example.com/');
+ // Space in ID and title
MT.test('[foo bar]: http://example.com/ "hello"',
'link', '[foo bar]:',
- 'string', ' http://example.com/',
- 'string', ' "hello"');
+ null, ' ',
+ 'string', 'http://example.com/ "hello"');
+ // Double title
+ MT.test('[foo bar]: http://example.com/ "hello" "world"',
+ 'link', '[foo bar]:',
+ null, ' ',
+ 'string', 'http://example.com/ "hello"',
+ null, ' "world"');
// Double quotes around title
MT.test('[foo]: http://example.com/ "bar"',
'link', '[foo]:',
- 'string', ' http://example.com/ "bar"');
+ null, ' ',
+ 'string', 'http://example.com/ "bar"');
// Single quotes around title
MT.test('[foo]: http://example.com/ \'bar\'',
'link', '[foo]:',
- 'string', ' http://example.com/ \'bar\'');
+ null, ' ',
+ 'string', 'http://example.com/ \'bar\'');
// Parentheses around title
MT.test('[foo]: http://example.com/ (bar)',
'link', '[foo]:',
- 'string', ' http://example.com/ (bar)');
+ null, ' ',
+ 'string', 'http://example.com/ (bar)');
// Invalid title
MT.test('[foo]: http://example.com/ bar',
'link', '[foo]:',
- 'string', ' http://example.com/',
+ null, ' ',
+ 'string', 'http://example.com/',
null, ' bar');
// Angle brackets around URL
MT.test('[foo]: Emphasis
@@ -255,96 +296,80 @@ Emphasis
// Single asterisk
MT.test('*foo* bar',
- 'em', '*',
- 'em', 'foo',
- 'em', '*',
+ 'em', '*foo*',
null, ' bar');
// Single underscore
MT.test('_foo_ bar',
- 'em', '_',
- 'em', 'foo',
- 'em', '_',
+ 'em', '_foo_',
null, ' bar');
// Emphasis characters within a word
MT.test('foo*bar*hello',
null, 'foo',
- 'em', '*',
- 'em', 'bar',
- 'em', '*',
+ 'em', '*bar*',
null, 'hello');
MT.test('foo_bar_hello',
null, 'foo',
- 'em', '_',
- 'em', 'bar',
- 'em', '_',
+ 'em', '_bar_',
null, 'hello');
// Per documentation: "...surround an * or _ with spaces, it’ll be
// treated as a literal asterisk or underscore."
+ //
+ // Inside EM
MT.test('foo _bar _ hello_ world',
- null, 'foo',
- 'em', '_',
- 'em', 'bar _ hello',
- 'em', '_',
+ null, 'foo ',
+ 'em', '_bar _ hello_',
+ null, ' world');
+ // Outside EM
+ MT.test('foo _ bar_hello_world',
+ null, 'foo _ bar',
+ 'em', '_hello_',
null, 'world');
// Unclosed emphasis characters
- // This should *not* be fixed by only adding the style to closed groups.
- // Instead, autocomplete should be added (see issue #344).
+ // Instead of simply marking as EM / STRONG, it would be nice to have an
+ // incomplete flag for EM and STRONG, that is styled slightly different.
MT.test('foo *bar',
- null, 'foo *bar');
+ null, 'foo ',
+ 'em', '*bar');
MT.test('foo _bar',
- null, 'foo _bar');
+ null, 'foo ',
+ 'em', '_bar');
// Double asterisk
MT.test('**foo** bar',
- 'strong', '**',
- 'strong', 'foo',
- 'strong', '**',
+ 'strong', '**foo**',
null, ' bar');
// Double underscore
MT.test('__foo__ bar',
- 'strong', '__',
- 'strong', 'foo',
- 'strong', '__',
+ 'strong', '__foo__',
null, ' bar');
// Triple asterisk
MT.test('*foo**bar*hello** world',
- 'em', '*',
- 'em', 'foo',
- 'emstrong', '**',
- 'emstrong', 'bar',
- 'emstrong', '*',
- 'strong', 'hello',
- 'strong', '**',
+ 'em', '*foo',
+ 'emstrong', '**bar*',
+ 'strong', 'hello**',
null, ' world');
// Triple underscore
MT.test('_foo__bar_hello__ world',
- 'em', '_',
- 'em', 'foo',
- 'emstrong', '__',
- 'emstrong', 'bar',
- 'emstrong', '_',
- 'strong', 'hello',
- 'strong', '__',
+ 'em', '_foo',
+ 'emstrong', '__bar_',
+ 'strong', 'hello__',
null, ' world');
// Triple mixed
// "...same character must be used to open and close an emphasis span.""
MT.test('_foo**bar*hello__ world',
- 'em', '_',
- 'em', 'foo**bar*hello',
- 'em', '_',
- null, '_ world');
+ 'em', '_foo',
+ 'emstrong', '**bar*hello__ world');
+
MT.test('*foo__bar_hello** world',
- 'em', '*',
- 'em', 'foo__bar_hello',
- 'em', '*',
- null, '* world');
+ 'em', '*foo',
+ 'emstrong', '__bar_hello** world');
Escaping
@@ -366,47 +391,27 @@ Escaping
//
// Backtick (code)
MT.test('foo \\`bar\\`',
- null, 'foo ',
- null, '\\`',
- null, 'bar',
- null, '\\`');
+ null, 'foo \\`bar\\`');
MT.test('foo \\\\`bar\\\\`',
- null, 'foo ',
- null, '\\\\',
+ null, 'foo \\\\',
'comment', '`bar\\\\`');
// Asterisk (em)
MT.test('foo \\*bar\\*',
- null, 'foo ',
- null, '\\*',
- null, 'bar',
- null, '\\*');
+ null, 'foo \\*bar\\*');
MT.test('foo \\\\*bar\\\\*',
- null, 'foo ',
- null, '\\\\',
- 'em', '*',
- 'em', 'bar',
- 'em', '\\\\',
- 'em', '*');
+ null, 'foo \\\\',
+ 'em', '*bar\\\\*');
// Underscore (em)
MT.test('foo \\_bar\\_',
- null, 'foo ',
- null, '\\_',
- null, 'bar',
- null, '\\_');
+ null, 'foo \\_bar\\_');
MT.test('foo \\\\_bar\\\\_',
- null, 'foo ',
- null, '\\\\',
- 'em', '_',
- 'em', 'bar',
- 'em', '\\\\',
- 'em', '_');
+ null, 'foo \\\\',
+ 'em', '_bar\\\\_');
// Hash mark (headers)
MT.test('\\# foo',
- null, '\\#',
- null, ' foo');
+ null, '\\# foo');
MT.test('\\\\# foo',
- null, '\\\\',
- null, '# foo');
+ null, '\\\\# foo');
Summary
diff --git a/mode/stex/test.html b/mode/stex/test.html
index 599e592dde..c63b3cbc31 100644
--- a/mode/stex/test.html
+++ b/mode/stex/test.html
@@ -20,8 +20,7 @@ Basics
null, 'foo');
MT.test('foo bar',
- null, 'foo',
- null, ' bar');
+ null, 'foo bar');
Tags
@@ -41,11 +40,7 @@ Tags
'bracket', '{',
'atom', 'equation',
'bracket', '}',
- null, ' ',
- null, ' ',
- null, 'E',
- null, '=mc',
- null, '^2',
+ null, ' E=mc^2',
'tag', '\\end',
'bracket', '{',
'atom', 'equation',
@@ -55,26 +50,21 @@ Tags
'tag', '\\begin',
'bracket', '{',
'atom', 'module',
- 'bracket', '}',
- 'bracket', '[',
- 'bracket', ']');
+ 'bracket', '}[]');
MT.test('\\begin{module}[id=bbt-size]',
'tag', '\\begin',
'bracket', '{',
'atom', 'module',
- 'bracket', '}',
- 'bracket', '[',
- null, 'id',
- null, '=bbt-size',
+ 'bracket', '}[',
+ null, 'id=bbt-size',
'bracket', ']');
MT.test('\\importmodule[b-b-t]{b-b-t}',
'tag', '\\importmodule',
'bracket', '[',
'string', 'b-b-t',
- 'bracket', ']',
- 'bracket', '{',
+ 'bracket', ']{',
'builtin', 'b-b-t',
'bracket', '}');
@@ -83,12 +73,8 @@ Tags
'bracket', '[',
'tag', '\\KWARCslides',
'bracket', '{',
- 'string', 'dmath',
- 'string', '/en',
- 'string', '/cardinality',
- 'bracket', '}',
- 'bracket', ']',
- 'bracket', '{',
+ 'string', 'dmath/en/cardinality',
+ 'bracket', '}]{',
'builtin', 'card',
'bracket', '}');
@@ -96,8 +82,7 @@ Tags
'tag', '\\PSforPDF',
'bracket', '[',
'atom', '1',
- 'bracket', ']',
- 'bracket', '{',
+ 'bracket', ']{',
null, '#1',
'bracket', '}');
@@ -105,18 +90,15 @@ Tags
Comments
Character Escapes
diff --git a/test/mode_test.js b/test/mode_test.js
index d77ac143f8..1479bd9280 100644
--- a/test/mode_test.js
+++ b/test/mode_test.js
@@ -85,11 +85,26 @@ ModeTest.highlight = function(string, mode) {
var line = lines[i];
var stream = new CodeMirror.StringStream(line);
if (line == "" && mode.blankLine) mode.blankLine(state);
+ var pos = 0;
+ var st = [];
+ /* Start copied code from CodeMirror.highlight */
while (!stream.eol()) {
- var style = mode.token(stream, state);
- var substr = line.slice(stream.start, stream.pos);
- output.push([style, substr]);
+ var style = mode.token(stream, state), substr = stream.current();
stream.start = stream.pos;
+ if (pos && st[pos-1] == style) {
+ st[pos-2] += substr;
+ } else if (substr) {
+ st[pos++] = substr; st[pos++] = style;
+ }
+ // Give up when line is ridiculously long
+ if (stream.pos > 5000) {
+ st[pos++] = this.text.slice(stream.pos); st[pos++] = null;
+ break;
+ }
+ }
+ /* End copied code from CodeMirror.highlight */
+ for (var x = 0; x < st.length; x += 2) {
+ output.push([st[x + 1], st[x]]);
}
}
@@ -131,7 +146,7 @@ ModeTest.prettyPrintOutputTable = function(output) {
var token = output[i];
s +=
'' +
- '' +
+ '' +
ModeTest.htmlEscape(token[1]).replace(/ /g,'·') +
'' +
' ';
From 367cfc6c8b5e184c667e6d2d83f6e29fcdac0761 Mon Sep 17 00:00:00 2001
From: Brandon Frohs Tests for the Markdown Mode
- Basics
+
+ Basics
+
@@ -167,6 +170,203 @@ Blockquotes
null, 'hello');
+ Lists
+
+
Horizontal rules
-
-
-
-
-
-
-
-
- Tests for the Markdown Mode
-
-
- Basics
-
-
- Code
-
-
- Headers
-
-
- Blockquotes
-
-
- Lists
-
-
- Horizontal rules
-
-
- Links
-
-
- Emphasis
-
-
- Escaping
-
-
- Summary
-
-
-
-