Permalink
Browse files

Allow styling of lines from mode tokenizers (experimental)

  • Loading branch information...
1 parent 687026e commit e0b0e32ed97bdd9b4dcb559f0d383bbb197961e4 @marijnh marijnh committed Sep 9, 2013
Showing with 44 additions and 12 deletions.
  1. +25 −12 lib/codemirror.js
  2. +19 −0 test/test.js
View
@@ -666,10 +666,11 @@ window.CodeMirror = (function() {
}
function buildLineElement(cm, line, lineNo, dims, reuse) {
- var lineElement = lineContent(cm, line);
+ var built = buildLineContent(cm, line), lineElement = built.pre;
var markers = line.gutterMarkers, display = cm.display, wrap;
- if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass && !line.widgets)
+ var bgClass = built.bgClass ? built.bgClass + " " + (line.bgClass || "") : line.bgClass;
+ if (!cm.options.lineNumbers && !markers && !bgClass && !line.wrapClass && !line.widgets)
return lineElement;
// Lines with gutter elements, widgets or a background class need
@@ -707,8 +708,8 @@ window.CodeMirror = (function() {
wrap.appendChild(lineElement);
}
// Kludge to make sure the styled element lies behind the selection (by z-index)
- if (line.bgClass)
- wrap.insertBefore(elt("div", null, line.bgClass + " CodeMirror-linebackground"), wrap.firstChild);
+ if (bgClass)
+ wrap.insertBefore(elt("div", null, bgClass + " CodeMirror-linebackground"), wrap.firstChild);
if (cm.options.lineNumbers || markers) {
var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absolute; left: " +
(cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
@@ -1031,7 +1032,7 @@ window.CodeMirror = (function() {
return crudelyMeasureLine(cm, line);
var display = cm.display, measure = emptyArray(line.text.length);
- var pre = lineContent(cm, line, measure, true);
+ var pre = buildLineContent(cm, line, measure, true).pre;
// IE does not cache element positions of inline elements between
// calls to getBoundingClientRect. This makes the loop below,
@@ -1135,7 +1136,7 @@ window.CodeMirror = (function() {
if (cached || line.text.length >= cm.options.crudeMeasuringFrom)
return measureChar(cm, line, line.text.length, cached && cached.measure, "right").right;
- var pre = lineContent(cm, line, null, true);
+ var pre = buildLineContent(cm, line, null, true).pre;
var end = pre.appendChild(zeroWidthElement(cm.display.measure));
removeChildrenAndAdd(cm.display.measure, pre);
return getRect(end).right - getRect(cm.display.lineDiv).left;
@@ -4314,21 +4315,30 @@ window.CodeMirror = (function() {
}
var styleToClassCache = {};
- function styleToClass(style) {
+ function interpretTokenStyle(style, builder) {
if (!style) return null;
+ for (;;) {
+ var lineClass = style.match(/(?:^|\s)line-(background-)?(\S+)/);
+ if (!lineClass) break;
+ style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length);
+ var prop = lineClass[1] ? "bgClass" : "textClass";
+ if (builder[prop] == null)
+ builder[prop] = lineClass[2];
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
+ builder[prop] += " " + lineClass[2];
+ }
return styleToClassCache[style] ||
(styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
}
- function lineContent(cm, realLine, measure, copyWidgets) {
+ function buildLineContent(cm, realLine, measure, copyWidgets) {
var merged, line = realLine, empty = true;
while (merged = collapsedSpanAtStart(line))
line = getLine(cm.doc, merged.find().from.line);
var builder = {pre: elt("pre"), col: 0, pos: 0,
measure: null, measuredSomething: false, cm: cm,
copyWidgets: copyWidgets};
- if (line.textClass) builder.pre.className = line.textClass;
do {
if (line.text) empty = false;
@@ -4365,8 +4375,11 @@ window.CodeMirror = (function() {
}
}
+ var textClass = builder.textClass ? builder.textClass + " " + (realLine.textClass || "") : realLine.textClass;
+ if (textClass) builder.pre.className = textClass;
+
signal(cm, "renderLine", cm, realLine, builder.pre);
- return builder.pre;
+ return builder;
}
var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g;
@@ -4477,7 +4490,7 @@ window.CodeMirror = (function() {
var spans = line.markedSpans, allText = line.text, at = 0;
if (!spans) {
for (var i = 1; i < styles.length; i+=2)
- builder.addToken(builder, allText.slice(at, at = styles[i]), styleToClass(styles[i+1]));
+ builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder));
return;
}
@@ -4527,7 +4540,7 @@ window.CodeMirror = (function() {
spanStartStyle = "";
}
text = allText.slice(at, at = styles[i++]);
- style = styleToClass(styles[i++]);
+ style = interpretTokenStyle(styles[i++], builder);
}
}
}
View
@@ -1539,3 +1539,22 @@ testCM("change_removedText", function(cm) {
eq(removedText[0].join("\n"), "abc\nd");
eq(removedText[1].join("\n"), "");
});
+
+testCM("lineStyleFromMode", function(cm) {
+ CodeMirror.defineMode("test_mode", function() {
+ return {token: function(stream) {
+ if (stream.match(/^\[[^\]]*\]/)) return "line-brackets";
+ if (stream.match(/^\([^\]]*\)/)) return "line-background-parens";
+ stream.match(/^\s+|^\S+/);
+ }};
+ });
+ cm.setOption("mode", "test_mode");
+ var bracketElts = byClassName(cm.getWrapperElement(), "brackets");
+ eq(bracketElts.length, 1);
+ eq(bracketElts[0].nodeName, "PRE");
+ is(!/brackets.*brackets/.test(bracketElts[0].className));
+ var parenElts = byClassName(cm.getWrapperElement(), "parens");
+ eq(parenElts.length, 1);
+ eq(parenElts[0].nodeName, "DIV");
+ is(!/parens.*parens/.test(parenElts[0].className));
+}, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: nothing"});

0 comments on commit e0b0e32

Please sign in to comment.