Search code examples
javascriptcodemirror

Finding the absolute start index of a {line, ch} object in CodeMirror


I'm trying to replace a highlighted bit of text in codemirror while retaining the original text. Say you have the following text in codemirror

Hi I'm 22

I'd like to replace 22 with 21. My function would return Hi I'm 21, while codemirror still reads the original text Hi I'm 22. I've got the 21 available as a marker, so I have a start and end index available.

I ended up with the following code

cm.replaceRange(..)
value = cm.getValue()
cm.undo()

This is fine, except that it's a little too slow for my use-case, the browser spends a lot of time doing dom and styling operations for the replaceRange and undo that are invisible to the user anyway, wasted cycles :(

So I came up with an alternate method, use cm.getValue(), calculate an absolute start and end index for the marker, split the cm.getValue() into before and after parts sandwiching 21 between them.

I've written the following function to do this, and it's mostly fine. It just goes bad sometimes, and I have literally no idea why, I've been debugging it for over 3 hours now.

function getIndexOfLineColumn(lineCh) {
    var lines  = editor.doc.children[0].lines;
    // Take all the lines, sum up their lengths up to but NOT including the line the character lies on
    // then add the column (lineCh.ch)
    var index  = lines.slice(0, lineCh.line).reduce(function (index, lineObj) {return index + lineObj.text.length + 1;}, 0) + lineCh.ch;
    return index;
}

One string I'm using is the following

// "Seascape" by Alexander Alekseev aka TDM - 2014
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

const int NUM_STEPS = 8;
const float PI      = 3.1415;
const float EPSILON = 1e-3;
float EPSILON_NRM   = 0.1 / iResolution.x;

// sea
const int ITER_GEOMETRY = 3;
const int ITER_FRAGMENT = 5;
const float SEA_HEIGHT = 0.6;
const float SEA_CHOPPY = 4.0;
const float SEA_SPEED = 0.8;
const float SEA_FREQ = 0.16;
const vec3 SEA_BASE = vec3(0.1,0.19,0.22);
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
float SEA_TIME = iGlobalTime * SEA_SPEED;
mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);

// math
mat3 fromEuler(vec3 ang) {
    vec2 a1 = vec2(sin(ang.x),cos(ang.x));
    vec2 a2 = vec2(sin(ang.y),cos(ang.y));
    vec2 a3 = vec2(sin(ang.z),cos(ang.z));
    mat3 m;
    m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
    m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
    m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
    return m;
}
float hash( vec2 p ) {
    float h = dot(p,vec2(127.1,311.7)); 
    return fract(sin(h)*43758.5453123);
}
float noise( in vec2 p ) {
    1.0;
    vec2 i = floor( p );
    vec2 f = fract( p );    
    vec2 u = f*f*(3.0-2.0*f);
    return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ), 
                     hash( i + vec2(1.0,0.0) ), u.x),
                mix( hash( i + vec2(0.0,1.0) ), 
                     hash( i + vec2(1.0,1.0) ), u.x), u.y);
}

If I mark the number 1.6 in the line mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);, then it correctly reports the starting index to be 598. If I mark the number 301 from the line vec2 u = f*f*(3.0-2.0*f); however, it incorrectly reports the index to be 1153, even though the index was supposed to be 1204, it's off by almost 50!

Does anybody have any idea why my method isn't working as expected, or has anyone written their own method to find an absolute index?


Solution

  • Did you see the indexFromPos and posFromIndex methods?