I'm trying to use CodeMirror (http://codemirror.net/) as a basic text editor with some extra functionalities. One of them is highlighting specific words or groups of words as specified by their positions in the original string. I have an external structure storing the list of substring positions I want to highlight. This structure is an Array where each element represents a text line and contains an array of objects with the positions of the substring to be highlighted. As an example, I have this text string:
The moon
is pale and round
as is
also the sun
The words to be highlighted are "moon", "pale", "round" and "sun". Thus, the highlighting structure is like this:
[
[ { iStart:4, iEnd:7 } ], // "moon"
[ { iStart:3, iEnd:6 }, { iStart:12, iEnd:16 } ], // "pale" and "round"
[],
[ { iStart:9, iEnd:11 } ] // "sun"
]
In order to achieve this, I first tried writing a custom language mode but was not successful (mainly because I didn't know how to manage the fact that CodeMirror seems to use tokens, not lines, and I obviously need to know the line where the current token is located so as to retrieve the right data from the highlight structure).
Then I tried writing an external function that applies the highlighting by just adding SPAN tags manually, like this:
function highlightText()
{
console.log( "highlightText()" );
// Get a reference to the text lines in the code editor
var codeLines = $("#editorContainer .CodeMirror-code pre>span" );
for( var i=0; i<colorSegments.length; i++ ){
// If there's text to be highlighted in this line...
if( colorSegments[i] && colorSegments[i].length > 0 ){
// Get the right element and do so
var lineElement = codeLines[i];
highlightWordsInLine( lineElement, colorSegments[i] );
}
}
}
function highlightWordsInLine(element, positions) {
// Get the raw text
var str = $( element ).text();
// Build a new string with highlighting tags.
// Start
var out = str.substr(0, positions[0].iStart);
for( var j=0; j<positions.length; j++ ){
var position = positions[j];
// Apply the highlighting tag
out += '<span class="cm-s-ambiance cm-relation">';
out += str.substr( position.iStart, position.iEnd - position.iStart + 1);
out += '</span>';
// Do not forget to incluide unhighlighted text in between
if( j < positions.length-1 ){
out += str.substr( position.iEnd - position.iStart + 1, positions[j+1].iStart );
}
}
// Wrap up to end of line
out += str.substr( position.iEnd + 1);
// Reset the html element value including applied highlight tags
element.innerHTML = out;
}
I understand this is a quite dirty approach, and it actually doesn't work 100% since some of the text in the code editor becomes unselectable and other bugs, but at least I got some success at controlling the highlighting.
So my question is, what's the right way to do this? If I should stick to the language-mode approach, how would I do it?
I've also been suggested to give a look to Ace (http://ace.c9.io/#nav=higlighter), but it doesn't look like it would support handling highlighting based on string positions instead of keyword lists or regexp rules.
Thanks in advance.
The
markText
method is designed to make this kind of thing easy.