I did end up coming with a solution to measure the position of a column in a line from renderLine and without relying on the defailtCharWidth. I don’t know how good it is but it works so I’ll post it here so others can use it maybe.
Basically I cut renderLine’s elt.innerHTML of at the given position preserving any tags. I then put that html in a separate measurement div and measure it (I tried to reuse cm.display.measure but it didn’t work). A caching can be added to improve performance:
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
lineWrapping: true,
mode: "text/html"
});
function htmlOffset(html, pos) {
function cutHTML(html, pos) { // cut html text at pos preserving all tags
var tag=false, symbol=false; res='', count=0;
for(var i=0; i<html.length; i++ ) {
if(html[i] === '<') tag = true;
if (tag || count<pos) res += html[i];
if (!tag) {
if (html[i] === '&') symbol=true;
if (symbol && html[i] === ';') symbol=false;
if (!symbol) count++; // note this counts the ';' of a symbol
}
if(html[i] === '>') tag = false;
}
return res;
}
var span=document.getElementById('htmlOffsetMeasurementSpan');
if (!span) { // create a 'dummy' span as the last child of 'CodeMirror'
span=document.createElement('span');
span.setAttribute("id", "htmlOffsetMeasurementSpan");
span.style.cssText = 'border:0;padding:0;'; // offsetWidth includes padding and border, explicitly override the style:
document.getElementsByClassName('CodeMirror')[0].appendChild(span);
}
// measure offset
span.innerHTML = cutHTML(html, pos).split(' ').join('\xA0'); // replace spaces with hard spaces
span.style.display = 'inline'; // show
var prefixWidth=span.offsetWidth;
span.style.display = 'none'; // hide
return prefixWidth;
}
var basePadding = 4;
editor.on("renderLine", function(cm, line, elt) {
var offstCol=CodeMirror.countColumn(line.text, null, cm.getOption("tabSize"));
var prefixWidth=htmlOffset(elt.innerHTML, offstCol);
elt.style.textIndent = "-" + prefixWidth + "px";
elt.style.paddingLeft = (basePadding + prefixWidth) + "px";
});
editor.refresh();