diff --git a/docs/bundle.js b/docs/bundle.js index 41b6071..47b8cda 100644 --- a/docs/bundle.js +++ b/docs/bundle.js @@ -147,7 +147,7 @@ module.exports = class CodeMirror extends Component { } } -},{"@codemirror/commands":45,"@codemirror/highlight":46,"@codemirror/lang-javascript":47,"@codemirror/state":51,"@codemirror/view":54,"choo/component":69,"choo/html":70}],2:[function(require,module,exports){ +},{"@codemirror/commands":24,"@codemirror/highlight":25,"@codemirror/lang-javascript":26,"@codemirror/state":30,"@codemirror/view":33,"choo/component":56,"choo/html":57}],2:[function(require,module,exports){ module.exports = { noise: { description: "Generate [Perlin noise](https://en.wikipedia.org/wiki/Perlin_noise).", @@ -156,6 +156,7 @@ module.exports = { code: `noise(10, 0.1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -165,6 +166,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) .out(o0)`, comments: { en: "noise interpolating between different scales and offsets", + es: "ruido (noise) cambiando entre varias escalas y offsets", ja: "noise の異なるスケールやオフセットを補間", } } @@ -177,6 +179,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `voronoi(5,0.3,0.3).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -184,6 +187,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `voronoi(25,2,10).color(1,1,0).brightness(0.15).out(o0)`, comments: { en: "fireflies", + es: "luciérnagas", ja: "蛍", } } @@ -195,6 +199,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc( [1,10,50,100,250,500].fast(2) ).out(o0)`, comments: { en: "frequency", + es: "frecuencia", ja: "周波数", } }, @@ -202,6 +207,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc( () => Math.sin(time/10) * 100 ).out(o0)`, comments: { en: "frequency 2", + es: "frecuencia 2", ja: "周波数 2", } }, @@ -209,6 +215,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc( 10, [-10,-1,-0.1,0,0.1,1,10], 0 ).out(o0)`, comments: { en: "sync", + es: "sincronización", ja: "シンク(同期)", } }, @@ -216,6 +223,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc(10,0.1, ({time}) => Math.sin(time/10) * 100 ).out(o0)`, comments: { en: "offset", + es: "offset", ja: "オフセット", } }, @@ -227,6 +235,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `shape(3,0.5,0.001).out(o0)`, comments: { en: "triangle", + es: "triángulo", ja: "三角形", } }, @@ -234,6 +243,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `shape(100,0.5,0.001).out(o0)`, comments: { en: "ellipse", + es: "elipse", ja: "楕円", } }, @@ -241,6 +251,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `shape(100,0.01,1).invert(()=>Math.sin(time)*2).out(o0)`, comments: { en: "inverting blurry circle", + es: "círculo difuminado que se invierte", ja: "反転するぼかした円", } }, @@ -256,6 +267,7 @@ shape(5,0.5,0.1).repeat(19,19) .out(o0)`, comments: { en: "a... rainbow ball?", + es: "una... ¿bola de arcoíris?", ja: "虹色のボール…?", } }, @@ -267,6 +279,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `gradient([1,2,4]).out(o0)`, comments: { en: "gradient sequence at speeds of 1, 2 & 4", + es: "secuencia de degradés con velocidades de 1, 2 y 4", ja: "グラデーションのスピードを 1, 2, 4 の順に変える", } }, @@ -274,6 +287,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `gradient(0).r().repeat(16,1).scrollX(0,0.1).out(o0)`, comments: { en: "saw oscillator", + es: "oscilador de cierra", ja: "のこぎり波", } }, @@ -286,6 +300,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `src(o0).modulate(noise(3),0.005).blend(shape(4),0.01).out(o0)`, comments: { en: "feedback", + es: "retroalimentación (feedback)", ja: "フィードバック", } }, @@ -297,6 +312,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `solid([1,0,0],[0,1,0],[0,0,1],1).out(o0)`, comments: { en: "cycling through red, green and blue", + es: "cambiando entre rojo, verde y azul", ja: "赤、緑、青を行き来する", } }, @@ -309,6 +325,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `osc(50).rotate( () => time%360 ).out(o0)`, comments: { en: "constant rotation", + es: "rotación constante", ja: "一定速度で回転", } }, @@ -319,6 +336,7 @@ osc(10,1,1) .out(o0)`, comments: { en: "modulate rotation speed", + es: "modulando la velocidad de rotación", ja: "回転速度を変化させる", } }, @@ -331,6 +349,7 @@ osc(10,1,1) code: `shape().scale(1.5,1,1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -345,6 +364,7 @@ shape().scale(1.5,[0.25,0.5,0.75,1].fast(0.25),[3,2,1]) .out(o0)`, comments: { en: "flower", + es: "flor", ja: "花", } }, @@ -357,6 +377,7 @@ shape().scale(1.5,[0.25,0.5,0.75,1].fast(0.25),[3,2,1]) code: `noise().pixelate(20,20).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -364,6 +385,7 @@ shape().scale(1.5,[0.25,0.5,0.75,1].fast(0.25),[3,2,1]) code: `noise().pixelate(2000,1).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -378,6 +400,7 @@ noise() .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -389,6 +412,7 @@ noise() code: `gradient(0).posterize( [1, 5, 15, 30] , 0.5 ).out(o0)`, comments: { en: "static gradient posterized, varying bins", + es: "gradiente estático, con una posterización cuya cantidad de tonos varía en el tiempo", ja: "", } }, @@ -396,6 +420,7 @@ noise() code: `gradient(0).posterize( 3, [0.1, 0.5, 1.0, 2.0] ).out(o0)`, comments: { en: "static gradient posterized, varying gamma", + es: "gradiente estático, con una posterización cuyo gamma varía en el tiempo", ja: "", } }, @@ -407,6 +432,7 @@ osc().posterize(3,1) .out(o0)`, comments: { en: "posterize (top); compare with pixelate (bottom)", + es: "posteriación (arriba); comparar con la pixelización (abajo)", ja: "", } }, @@ -418,6 +444,7 @@ osc().posterize(3,1) code: `osc().shift(0.1,0.9,0.3).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -429,6 +456,7 @@ osc().posterize(3,1) code: `shape().repeat(3.0, 3.0, 0.0, 0.0).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -441,6 +469,7 @@ shape(1.25,0.5,0.25) .out(o0)`, comments: { en: "dogtooth factory", + es: "pata de gallo", ja: "", } }, @@ -457,6 +486,7 @@ shape(4,0.9) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -468,6 +498,7 @@ shape(4,0.9) code: `shape().repeatX(3.0, 0.0).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -479,6 +510,7 @@ osc(5,0,1) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -496,6 +528,7 @@ shape(4,0.9) .out(o0)`, comments: { en: "straight lines illusion", + es: "ilusión de líneas rectas", ja: "", } }, @@ -507,6 +540,7 @@ shape(4,0.9) code: `shape().repeatY(3.0, 0.0).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -517,6 +551,7 @@ osc(5,0,1) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -534,6 +569,7 @@ shape(4,0.9) .out(o0)`, comments: { en: "morphing grid", + es: "cuadrícula cambiante", ja: "", } }, @@ -546,6 +582,7 @@ shape(4,0.9) code: `osc(25,-0.1,0.5).kaleid(50).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -553,6 +590,7 @@ shape(4,0.9) code: `osc(25,-0.1,0.5).kaleid(4).kaleid(4).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -571,6 +609,7 @@ osc(9,-0.1,0.1) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -580,6 +619,7 @@ osc(9,-0.1,0.1) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -591,6 +631,7 @@ osc(9,-0.1,0.1) code: `shape(3).scroll(0.1,-0.3).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -602,6 +643,7 @@ osc(9,-0.1,0.1) code: `osc(10,0,1).scrollX(0.5,0).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -609,6 +651,7 @@ osc(9,-0.1,0.1) code: `osc(10,0,1).scrollX([0,0.25,0.5,0.75,1].fast(4),0).out(o0)`, comments: { en: "x position", + es: "posición x (horizontal)", ja: "", } }, @@ -616,6 +659,7 @@ osc(9,-0.1,0.1) code: `gradient(1).scrollX(0, () => Math.sin(time*0.05)*0.05 ).out(o0)`, comments: { en: "scroll speed", + es: "velocidad de desplazamiento (scroll)", ja: "", } }, @@ -629,6 +673,7 @@ osc(9,-0.1,0.1) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -644,6 +689,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -654,6 +700,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "different scroll and speed", + es: "distinto desplazamiento y velocidad", ja: "", } }, @@ -665,6 +712,7 @@ voronoi(25,0,0) code: `osc(10,0,1).scrollY(0.5,0).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -672,6 +720,7 @@ voronoi(25,0,0) code: `osc(10,0,1).scrollY([0,0.25,0.5,0.75,1].fast(4),0).out(o0)`, comments: { en: "y position", + es: "posición y (vertical)", ja: "", } }, @@ -679,6 +728,7 @@ voronoi(25,0,0) code: `gradient(1).scrollY(0, ({time}) => Math.sin(time*0.05)*0.05 ).out()`, comments: { en: "scroll speed", + es: "velocidad de desplazamiento (scroll)", ja: "", } }, @@ -707,6 +757,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -717,6 +768,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "different scroll and speed", + es: "distinto desplazamiento y velocidad", ja: "", } }, @@ -729,6 +781,7 @@ voronoi(25,0,0) code: `shape().scale(0.5).add(shape(4),[0,0.25,0.5,0.75,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -736,6 +789,7 @@ voronoi(25,0,0) code: `osc(9,0.1,1).add(osc(13,0.5,5)).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -747,6 +801,7 @@ voronoi(25,0,0) code: `osc().sub(osc(6)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -754,6 +809,7 @@ voronoi(25,0,0) code: `osc(6,0,1.5).modulate(noise(3).sub(gradient()),1).out(o0)`, comments: { en: "color remapping", + es: "reasignación de colores", ja: "", } }, @@ -766,6 +822,7 @@ voronoi(25,0,0) code: `solid(1,0,0,1).layer(shape(4).color(0,1,0,()=>Math.sin(time*2))).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -773,6 +830,7 @@ voronoi(25,0,0) code: `osc(30).layer(osc(15).rotate(1).luma()).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -785,6 +843,7 @@ voronoi(25,0,0) code: `shape().scale(0.5).blend(shape(4),[0,0.25,0.5,0.75,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -792,6 +851,7 @@ voronoi(25,0,0) code: `osc(9,0.1,1).blend(osc(13,0.5,5)).out()`, comments: { en: "", + es: "", ja: "", } }, @@ -799,6 +859,7 @@ voronoi(25,0,0) code: `osc().thresh().blend(o0,0.9).out(o0)`, comments: { en: "motion-blur like feedback", + es: "feedback con apariencia difuminada", ja: "", } }, @@ -811,6 +872,7 @@ voronoi(25,0,0) code: `osc(9,0.1,2).mult(osc(13,0.5,5)).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -821,6 +883,7 @@ osc() .out(o0)`, comments: { en: "mult is *not* transparent; compare with mask", + es: "mult *no* es transparente; compárese con mask", ja: "", } }, @@ -833,6 +896,7 @@ osc() code: `osc(9,0.1,1).diff(osc(13,0.5,5)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -846,6 +910,7 @@ osc(1,1,2) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -867,6 +932,7 @@ voronoi() .out(o0)`, comments: { en: "chocolate whirlpool", + es: "remolino de chocolate", ja: "", } }, @@ -877,6 +943,7 @@ osc(3,0,2) .out(o0)`, comments: { en: "color remapping", + es: "reasignación de colores", ja: "", } }, @@ -892,6 +959,7 @@ gradient(5).repeat(50,50).kaleid([3,5,7,9].fast(0.5)) .out(o0)`, comments: { en: "cosmic radiation", + es: "radiación cósmica", ja: "", } }, @@ -899,6 +967,7 @@ gradient(5).repeat(50,50).kaleid([3,5,7,9].fast(0.5)) code: `shape(4).modulateScale(gradient().g(),2,0.5).out(o0)`, comments: { en: "perspective", + es: "perspectiva", ja: "", } }, @@ -914,6 +983,7 @@ voronoi(10,1,5).brightness(()=>Math.random()*0.15) .out(o0)`, comments: { en: "what lies beneath", + es: "lo que se encuentra por debajo", ja: "", } }, @@ -923,6 +993,7 @@ noise(3).modulatePixelate(noise(3).pixelate(8,8),1024,8) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -939,6 +1010,7 @@ voronoi(100,3,5) .out(o0)`, comments: { en: "wormhole", + es: "agujero de gusano", ja: "", } }, @@ -946,6 +1018,7 @@ voronoi(100,3,5) code: `osc().modulateRotate(shape(999,0.3,0.5),1.57).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -962,6 +1035,7 @@ src(o0) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -974,6 +1048,7 @@ src(o0) code: `solid(1,1,1).invert([0,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -984,6 +1059,7 @@ osc(4,0.1,2).invert().luma().invert() .mask(shape(2,0.5).scrollY(-0.25))).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -996,6 +1072,7 @@ osc(4,0.1,2).invert().luma().invert() code: `osc(20).contrast( () => Math.sin(time) * 5 ).out(o0)`, comments: { en: "20Hz oscillator with contrast interpolating between 0.0-5.0", + es: "oscilador a 20Hz con un contraste que cambia entre 0.0-5.0", ja: "", } }, @@ -1010,6 +1087,7 @@ osc(20,0,2) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1017,6 +1095,7 @@ osc(20,0,2) code: `noise().brightness(1).color(0.5,0.5,0.5).out(o0)`, comments: { en: "scaling noise value to 0-1", + es: "escalando el valor de noise a un rango de 0-1", ja: "", } }, @@ -1028,6 +1107,7 @@ osc(20,0,2) code: `gradient(5).mask(voronoi(),3,0.5).invert([0,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1038,6 +1118,7 @@ osc() .out(o0)`, comments: { en: "mask is transparent; compare with mult", + es: "mask es transparente; compárese con mult", ja: "", } }, @@ -1051,6 +1132,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) .out(o0)`, comments: { en: "algae pulse", + es: "pulso de algas", ja: "", } }, @@ -1062,6 +1144,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `osc(10,0,1).luma(0.5,0.1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1069,6 +1152,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `osc(10,0,[0,0.5,1,2]).luma([0.1,0.25,0.75,1].fast(0.25),0.1).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1076,6 +1160,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `osc(30).layer(osc(15).rotate(1).luma()).out(o0)`, comments: { en: "luma is transparent; compare with thresh", + es: "luma es transparente; compárese con thresh", ja: "", } }, @@ -1087,6 +1172,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `noise(3,0.1).thresh(0.5,0.04).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1097,6 +1183,7 @@ noise(3,0.1) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1104,6 +1191,7 @@ noise(3,0.1) code: `osc(30).layer(osc(15).rotate(1).thresh()).out(o0)`, comments: { en: "thresh is *not* transparent; compare with luma", + es: "thresh *no* es transparente; compárese con luma", ja: "", } }, @@ -1115,6 +1203,7 @@ noise(3,0.1) code: `osc().color(1,0,3).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1126,6 +1215,7 @@ noise(3,0.1) code: `osc(10,0,1).saturate( () => Math.sin(time) * 10 ).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1137,6 +1227,7 @@ noise(3,0.1) code: `osc(30,0.1,1).hue(() => Math.sin(time)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1157,6 +1248,11 @@ osc(20) // color sequence of Red, Green, Blue, White, Black // colorama sequence of 0.005, 0.5, 1.0 at 1/8 speed // output to buffer o0`, + es: ` +// oscilador de 20Hz +// secuencia de color que cambia entre rojo, verde, azul, blanco y negro +// secuencia de colorama de 0.005, 0.5, 1.0 a un octavo de velocidad +// salida al buffer o0`, ja: "デフォルト", } }, @@ -1164,6 +1260,7 @@ osc(20) code: `osc(30,0.1,1).colorama(-0.1).out(o0)`, comments: { en: "negative value is less harsh", + es: "los valores negativos son más suaves", ja: "", } }, @@ -1175,6 +1272,7 @@ osc(20) code: `osc(60,0.1,1.5).layer(gradient().r()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1186,6 +1284,7 @@ osc(20) code: `osc(60,0.1,1.5).layer(gradient().g()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1197,6 +1296,7 @@ osc(20) code: `osc(60,0.1,1.5).layer(gradient().colorama(1).b()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1210,6 +1310,7 @@ s0.initCam() src(s0).invert().out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1223,6 +1324,7 @@ s0.initImage("https://upload.wikimedia.org/wikipedia/commons/2/25/Hydra-Foto.jpg osc(6).modulate(src(s0),1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1236,6 +1338,7 @@ s0.initVideo("https://media.giphy.com/media/AS9LIFttYzkc0/giphy.mp4") src(s0).modulate(noise(3)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1255,6 +1358,7 @@ s0.init({src:canvas}) src(s0).modulate(osc().kaleid(999)).out(o0)`, comments: { en: "load canvas", + es: "cargar canvas", ja: "canvas をロード", } }, @@ -1268,6 +1372,7 @@ s0.initScreen() src(s0).colorama(0.5).out(o0)`, comments: { en: "select a window", + es: "selecciona una ventana", ja: "画面を選択", } }, @@ -1284,6 +1389,7 @@ gradient().out(o3) render()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1293,6 +1399,7 @@ voronoi().out(o1) render(o1)`, comments: { en: "specify display buffer", + es: "especifica salida a renderizar", ja: "", } }, @@ -1307,6 +1414,7 @@ update = () => b += 0.01 * Math.sin(time) shape().scrollX(()=>b).out(o0)`, comments: { en: "update is called every frame", + es: "update es llamada cada fotograma", ja: "", } }, @@ -1320,6 +1428,7 @@ setResolution(100,100) osc().out(o0)`, comments: { en: "make the canvas small (100 pixel x 100 pixel)", + es: "hace al canvas muy pequeño (100 pixeles x 100 pixeles)", ja: "", } }, @@ -1333,6 +1442,7 @@ osc().out(o0) hush()`, comments: { en: "clear the buffers", + es: "limpia los buffers", ja: "", } }, @@ -1358,6 +1468,7 @@ setFunction({ osc(60,0.1,1.5).chroma().out(o0)`, comments: { en: "from https://www.shadertoy.com/view/XsfGzn", + es: "sacado de https://www.shadertoy.com/view/XsfGzn", ja: "", } }, @@ -1371,6 +1482,7 @@ speed = 3 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change overall speed", + es: "cambia la velocidad global", ja: "", } }, @@ -1380,6 +1492,7 @@ speed = 0.1 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change overall speed", + es: "cambia la velocidad global", ja: "", } }, @@ -1393,6 +1506,7 @@ bpm = 60 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change array speed", + es: "cambia la velocidad de los arrays", ja: "", } }, @@ -1402,6 +1516,7 @@ bpm = 15 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change array speed", + es: "cambia la velocidad de los arrays", ja: "", } }, @@ -1414,6 +1529,7 @@ osc(60,0.1,[0,1.5]).out(o0)`, shape(99).scrollX(() => -mouse.x / width).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1426,6 +1542,7 @@ shape(99).scrollX(() => -mouse.x / width).out(o0)`, shape(99).scrollY(() => -mouse.y / height).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1437,6 +1554,7 @@ shape(99).scrollY(() => -mouse.y / height).out(o0)`, code: `shape(2,0.8).kaleid(()=>6+Math.sin(time)*4).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1452,6 +1570,7 @@ shape(99).scroll( .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1463,6 +1582,7 @@ shape(99).scroll( code: `osc([10,30,60].fast(2),0.1,1.5).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1470,6 +1590,7 @@ shape(99).scroll( code: `osc([10,30,60].fast(0.5),0.1,1.5).out(o0)`, comments: { en: "argument less than 1 makes transition slower", + es: "un argumento menor a 1 hace a las transiciones más lentas", ja: "", } }, @@ -1481,6 +1602,7 @@ shape(99).scroll( code: `shape(999).scrollX([-0.2,0.2].smooth()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1492,6 +1614,7 @@ shape(99).scroll( code: `shape(4).rotate([-3.14,3.14].ease('easeInOutCubic')).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1507,6 +1630,7 @@ shape(999).scrollY(.2).scrollX([-0.2,0.2]) ).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1518,6 +1642,7 @@ shape(999).scrollY(.2).scrollX([-0.2,0.2]) code: `shape().scrollX([0,1,2,3,4].fit(-0.2,0.2)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1529,6 +1654,7 @@ shape(999).scrollY(.2).scrollX([-0.2,0.2]) code: `osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1542,6 +1668,7 @@ a.setSmooth(0.8) osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1555,6 +1682,7 @@ a.setCutoff(4) osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "threshold", + es: "umbral (threshold)", ja: "", } }, @@ -1568,6 +1696,7 @@ a.setBins(8) osc(60,0.1,()=>a.fft[7]*3).modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "change color with hissing noise", + es: "cambiando el color con ruido", ja: "", } }, @@ -1581,6 +1710,7 @@ a.setScale(5) osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "the smaller the scale is, the bigger the output is", + es: "cuanto menor la escala, mayor es la salida", ja: "", } }, @@ -1935,7 +2065,7 @@ class HydraReference { module.exports = () => new HydraReference -},{"./examples.js":2,"./hydra-plugins.js":3,"./types.js":28,"hydra-synth/src/glsl/glsl-functions":15}],5:[function(require,module,exports){ +},{"./examples.js":2,"./hydra-plugins.js":3,"./types.js":134,"hydra-synth/src/glsl/glsl-functions":73}],5:[function(require,module,exports){ var html = require('choo/html') var Component = require('choo/component') const HydraSynth = require('hydra-synth') @@ -1961,7 +2091,7 @@ module.exports = class Hydra extends Component { } } -},{"choo/component":69,"choo/html":70,"hydra-synth":9}],6:[function(require,module,exports){ +},{"choo/component":56,"choo/html":57,"hydra-synth":67}],6:[function(require,module,exports){ const html = require('choo/html') const raw = require('choo/html/raw') const devtools = require('choo-devtools') @@ -2167,7 +2297,7 @@ function mainView (state, emit) {
emit('clear details') }> ${i18next.t('title')}
- ${state.page.selected === null ? '' : `::: ${state.page.selected.name}`} + ${state.page.selected === null ? '' : ` ::: ${state.page.selected.name}`}
${ languageView(state, emit) }
@@ -2264,7 +2394,7 @@ function store (state, emitter) { }) } -},{"./codemirror.js":1,"./hydra-reference.js":4,"./hydra.js":5,"./locales.js":7,"choo":72,"choo-devtools":58,"choo/html":70,"choo/html/raw":71,"i18next":82,"i18next-browser-languagedetector":81}],7:[function(require,module,exports){ +},{"./codemirror.js":1,"./hydra-reference.js":4,"./hydra.js":5,"./locales.js":7,"choo":59,"choo-devtools":45,"choo/html":57,"choo/html/raw":58,"i18next":89,"i18next-browser-languagedetector":88}],7:[function(require,module,exports){ const html = require('choo/html') module.exports = { en: { @@ -2291,6 +2421,30 @@ module.exports = { 'openin': 'open in editor', } }, + es: { + translation: { + 'language-name': 'Spanish', + 'example': 'Ejemplo', + 'usage': 'Uso', + 'title': 'Funciones de hydra', + 'intro': `Hay 5 tipos de funciones en hydra: señales generadoras (sources), de geometría, de color, de fusón, y de modulación. + Haz click en cualquier función aquí abajo para ver su uso. (Para una documentación más detallada, puedes ver la página web de hydra, + primeros pasos o el Hydra Book.)`, + 'editor-info': 'Edita el código y presiona el botón "▶" o usa "ctrl+enter" para ejecutarlo!', + 'src': 'Source', + 'coord': 'Geometría', + 'color': 'Color', + 'combine': 'Fusión', + 'combineCoord': 'Modulación', + 'ext': 'Fuentes externas', + 'settings': 'Ajustes del sintetizador', + 'array': 'Array', + 'audio': 'Audio', + 'run': 'ejecutar', + 'reset': 'reset', + 'openin': 'abrir en el editor', + } + }, ja: { translation: { 'language-name': '日本語', @@ -2317,24146 +2471,24286 @@ module.exports = { } } -},{"choo/html":70}],8:[function(require,module,exports){ -const Output = require('./src/output.js') -const loop = require('raf-loop') -const Source = require('./src/hydra-source.js') -const Mouse = require('./src/lib/mouse.js')() -const Audio = require('./src/lib/audio.js') -const VidRecorder = require('./src/lib/video-recorder.js') -const ArrayUtils = require('./src/lib/array-utils.js') -const Sandbox = require('./src/eval-sandbox.js') - -const Generator = require('./src/generator-factory.js') - -// to do: add ability to pass in certain uniforms and transforms -class HydraRenderer { - - constructor ({ - pb = null, - width = 1280, - height = 720, - numSources = 4, - numOutputs = 4, - makeGlobal = true, - autoLoop = true, - detectAudio = true, - enableStreamCapture = true, - canvas, - precision, - extendTransforms = {} // add your own functions on init - } = {}) { - - ArrayUtils.init() - - this.pb = pb - - this.width = width - this.height = height - this.renderAll = false - this.detectAudio = detectAudio - - this._initCanvas(canvas) - +},{"choo/html":57}],8:[function(require,module,exports){ +function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; - // object that contains all properties that will be made available on the global context and during local evaluation - this.synth = { - time: 0, - bpm: 30, - width: this.width, - height: this.height, - fps: undefined, - stats: { - fps: 0 - }, - speed: 1, - mouse: Mouse, - render: this._render.bind(this), - setResolution: this.setResolution.bind(this), - update: (dt) => {},// user defined update function - hush: this.hush.bind(this) - } + for (var i = 0, arr2 = new Array(len); i < len; i++) { + arr2[i] = arr[i]; + } - if (makeGlobal) window.loadScript = this.loadScript + return arr2; +} +module.exports = _arrayLikeToArray, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],9:[function(require,module,exports){ +function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; +} - this.timeSinceLastUpdate = 0 - this._time = 0 // for internal use, only to use for deciding when to render frames +module.exports = _arrayWithHoles, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],10:[function(require,module,exports){ +function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } - // only allow valid precision options - let precisionOptions = ['lowp','mediump','highp'] - if(precision && precisionOptions.includes(precision.toLowerCase())) { - this.precision = precision.toLowerCase() - // - // if(!precisionValid){ - // console.warn('[hydra-synth warning]\nConstructor was provided an invalid floating point precision value of "' + precision + '". Using default value of "mediump" instead.') - // } - } else { - let isIOS = - (/iPad|iPhone|iPod/.test(navigator.platform) || - (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) && - !window.MSStream; - this.precision = isIOS ? 'highp' : 'mediump' - } + return self; +} +module.exports = _assertThisInitialized, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],11:[function(require,module,exports){ +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} +module.exports = _classCallCheck, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],12:[function(require,module,exports){ +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } +} - this.extendTransforms = extendTransforms +function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; +} - // boolean to store when to save screenshot - this.saveFrame = false +module.exports = _createClass, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],13:[function(require,module,exports){ +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } - // if stream capture is enabled, this object contains the capture stream - this.captureStream = null + return obj; +} - this.generator = undefined +module.exports = _defineProperty, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],14:[function(require,module,exports){ +function _getPrototypeOf(o) { + module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }, module.exports.__esModule = true, module.exports["default"] = module.exports; + return _getPrototypeOf(o); +} - this._initRegl() - this._initOutputs(numOutputs) - this._initSources(numSources) - this._generateGlslTransforms() +module.exports = _getPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],15:[function(require,module,exports){ +var setPrototypeOf = require("./setPrototypeOf.js"); - this.synth.screencap = () => { - this.saveFrame = true - } +function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } - if (enableStreamCapture) { - try { - this.captureStream = this.canvas.captureStream(25) - // to do: enable capture stream of specific sources and outputs - this.synth.vidRecorder = new VidRecorder(this.captureStream) - } catch (e) { - console.warn('[hydra-synth warning]\nnew MediaSource() is not currently supported on iOS.') - console.error(e) - } + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + writable: true, + configurable: true } + }); + Object.defineProperty(subClass, "prototype", { + writable: false + }); + if (superClass) setPrototypeOf(subClass, superClass); +} - if(detectAudio) this._initAudio() - - if(autoLoop) loop(this.tick.bind(this)).start() - - // final argument is properties that the user can set, all others are treated as read-only - this.sandbox = new Sandbox(this.synth, makeGlobal, ['speed', 'update', 'bpm', 'fps']) - } - - eval(code) { - this.sandbox.eval(code) - } +module.exports = _inherits, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{"./setPrototypeOf.js":19}],16:[function(require,module,exports){ +function _iterableToArray(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); +} - getScreenImage(callback) { - this.imageCallback = callback - this.saveFrame = true - } +module.exports = _iterableToArray, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],17:[function(require,module,exports){ +function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} - hush() { - this.s.forEach((source) => { - source.clear() - }) - this.o.forEach((output) => { - this.synth.solid(0, 0, 0, 0).out(output) - }) - this.synth.render(this.o[0]) - } +module.exports = _nonIterableRest, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],18:[function(require,module,exports){ +var _typeof = require("./typeof.js")["default"]; - loadScript(url = "") { - const p = new Promise((res, rej) => { - var script = document.createElement("script"); - script.onload = function () { - console.log(`loaded script ${url}`); - res(); - }; - script.onerror = (err) => { - console.log(`error loading script ${url}`, "log-error"); - res() - }; - script.src = url; - document.head.appendChild(script); - }); - return p; - } +var assertThisInitialized = require("./assertThisInitialized.js"); - setResolution(width, height) { - // console.log(width, height) - this.canvas.width = width - this.canvas.height = height - this.width = width // is this necessary? - this.height = height // ? - this.sandbox.set('width', width) - this.sandbox.set('height', height) - console.log(this.width) - this.o.forEach((output) => { - output.resize(width, height) - }) - this.s.forEach((source) => { - source.resize(width, height) - }) - this.regl._refresh() - console.log(this.canvas.width) +function _possibleConstructorReturn(self, call) { + if (call && (_typeof(call) === "object" || typeof call === "function")) { + return call; + } else if (call !== void 0) { + throw new TypeError("Derived constructors may only return object or undefined"); } - canvasToImage (callback) { - const a = document.createElement('a') - a.style.display = 'none' - - let d = new Date() - a.download = `hydra-${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}-${d.getHours()}.${d.getMinutes()}.${d.getSeconds()}.png` - document.body.appendChild(a) - var self = this - this.canvas.toBlob( (blob) => { - if(self.imageCallback){ - self.imageCallback(blob) - delete self.imageCallback - } else { - a.href = URL.createObjectURL(blob) - console.log(a.href) - a.click() - } - }, 'image/png') - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(a.href); - }, 300); - } + return assertThisInitialized(self); +} - _initAudio () { - const that = this - this.synth.a = new Audio({ - numBins: 4, - // changeListener: ({audio}) => { - // that.a = audio.bins.map((_, index) => - // (scale = 1, offset = 0) => () => (audio.fft[index] * scale + offset) - // ) - // - // if (that.makeGlobal) { - // that.a.forEach((a, index) => { - // const aname = `a${index}` - // window[aname] = a - // }) - // } - // } - }) - } +module.exports = _possibleConstructorReturn, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{"./assertThisInitialized.js":10,"./typeof.js":21}],19:[function(require,module,exports){ +function _setPrototypeOf(o, p) { + module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }, module.exports.__esModule = true, module.exports["default"] = module.exports; + return _setPrototypeOf(o, p); +} - // create main output canvas and add to screen - _initCanvas (canvas) { - if (canvas) { - this.canvas = canvas - this.width = canvas.width - this.height = canvas.height - } else { - this.canvas = document.createElement('canvas') - this.canvas.width = this.width - this.canvas.height = this.height - this.canvas.style.width = '100%' - this.canvas.style.height = '100%' - this.canvas.style.imageRendering = 'pixelated' - document.body.appendChild(this.canvas) - } - } +module.exports = _setPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],20:[function(require,module,exports){ +var arrayWithHoles = require("./arrayWithHoles.js"); - _initRegl () { - this.regl = require('regl')({ - // profile: true, - canvas: this.canvas, - pixelRatio: 1//, - // extensions: [ - // 'oes_texture_half_float', - // 'oes_texture_half_float_linear' - // ], - // optionalExtensions: [ - // 'oes_texture_float', - // 'oes_texture_float_linear' - //] - }) +var iterableToArray = require("./iterableToArray.js"); - // This clears the color buffer to black and the depth buffer to 1 - this.regl.clear({ - color: [0, 0, 0, 1] - }) +var unsupportedIterableToArray = require("./unsupportedIterableToArray.js"); - this.renderAll = this.regl({ - frag: ` - precision ${this.precision} float; - varying vec2 uv; - uniform sampler2D tex0; - uniform sampler2D tex1; - uniform sampler2D tex2; - uniform sampler2D tex3; +var nonIterableRest = require("./nonIterableRest.js"); - void main () { - vec2 st = vec2(1.0 - uv.x, uv.y); - st*= vec2(2); - vec2 q = floor(st).xy*(vec2(2.0, 1.0)); - int quad = int(q.x) + int(q.y); - st.x += step(1., mod(st.y,2.0)); - st.y += step(1., mod(st.x,2.0)); - st = fract(st); - if(quad==0){ - gl_FragColor = texture2D(tex0, st); - } else if(quad==1){ - gl_FragColor = texture2D(tex1, st); - } else if (quad==2){ - gl_FragColor = texture2D(tex2, st); - } else { - gl_FragColor = texture2D(tex3, st); - } +function _toArray(arr) { + return arrayWithHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableRest(); +} - } - `, - vert: ` - precision ${this.precision} float; - attribute vec2 position; - varying vec2 uv; +module.exports = _toArray, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{"./arrayWithHoles.js":9,"./iterableToArray.js":16,"./nonIterableRest.js":17,"./unsupportedIterableToArray.js":22}],21:[function(require,module,exports){ +function _typeof(obj) { + "@babel/helpers - typeof"; - void main () { - uv = position; - gl_Position = vec4(1.0 - 2.0 * position, 0, 1); - }`, - attributes: { - position: [ - [-2, 0], - [0, -2], - [2, 2] - ] - }, - uniforms: { - tex0: this.regl.prop('tex0'), - tex1: this.regl.prop('tex1'), - tex2: this.regl.prop('tex2'), - tex3: this.regl.prop('tex3') - }, - count: 3, - depth: { enable: false } - }) + return (module.exports = _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj); +} - this.renderFbo = this.regl({ - frag: ` - precision ${this.precision} float; - varying vec2 uv; - uniform vec2 resolution; - uniform sampler2D tex0; +module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{}],22:[function(require,module,exports){ +var arrayLikeToArray = require("./arrayLikeToArray.js"); - void main () { - gl_FragColor = texture2D(tex0, vec2(1.0 - uv.x, uv.y)); - } - `, - vert: ` - precision ${this.precision} float; - attribute vec2 position; - varying vec2 uv; +function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen); +} - void main () { - uv = position; - gl_Position = vec4(1.0 - 2.0 * position, 0, 1); - }`, - attributes: { - position: [ - [-2, 0], - [0, -2], - [2, 2] - ] - }, - uniforms: { - tex0: this.regl.prop('tex0'), - resolution: this.regl.prop('resolution') - }, - count: 3, - depth: { enable: false } - }) - } +module.exports = _unsupportedIterableToArray, module.exports.__esModule = true, module.exports["default"] = module.exports; +},{"./arrayLikeToArray.js":8}],23:[function(require,module,exports){ +'use strict'; - _initOutputs (numOutputs) { - const self = this - this.o = (Array(numOutputs)).fill().map((el, index) => { - var o = new Output({ - regl: this.regl, - width: this.width, - height: this.height, - precision: this.precision, - label: `o${index}` - }) - // o.render() - o.id = index - self.synth['o'+index] = o - return o - }) +Object.defineProperty(exports, '__esModule', { value: true }); - // set default output - this.output = this.o[0] - } +var state = require('@codemirror/state'); +var view = require('@codemirror/view'); +var tooltip = require('@codemirror/tooltip'); +var language = require('@codemirror/language'); +var text = require('@codemirror/text'); - _initSources (numSources) { - this.s = [] - for(var i = 0; i < numSources; i++) { - this.createSource(i) +/** +An instance of this is passed to completion source functions. +*/ +class CompletionContext { + /** + Create a new completion context. (Mostly useful for testing + completion sources—in the editor, the extension will create + these for you.) + */ + constructor( + /** + The editor state that the completion happens in. + */ + state, + /** + The position at which the completion is happening. + */ + pos, + /** + Indicates whether completion was activated explicitly, or + implicitly by typing. The usual way to respond to this is to + only return completions when either there is part of a + completable entity before the cursor, or `explicit` is true. + */ + explicit) { + this.state = state; + this.pos = pos; + this.explicit = explicit; + /** + @internal + */ + this.abortListeners = []; } - } - - createSource (i) { - let s = new Source({regl: this.regl, pb: this.pb, width: this.width, height: this.height, label: `s${i}`}) - this.synth['s' + this.s.length] = s - this.s.push(s) - return s - } - - _generateGlslTransforms () { - var self = this - this.generator = new Generator({ - defaultOutput: this.o[0], - defaultUniforms: this.o[0].uniforms, - extendTransforms: this.extendTransforms, - changeListener: ({type, method, synth}) => { - if (type === 'add') { - self.synth[method] = synth.generators[method] - if(self.sandbox) self.sandbox.add(method) - } else if (type === 'remove') { - // what to do here? dangerously deleting window methods - //delete window[method] - } - // } - } - }) - this.synth.setFunction = this.generator.setFunction.bind(this.generator) - } - - _render (output) { - if (output) { - this.output = output - this.isRenderingAll = false - } else { - this.isRenderingAll = true - } - } - - // dt in ms - tick (dt, uniforms) { - this.sandbox.tick() - if(this.detectAudio === true) this.synth.a.tick() - // let updateInterval = 1000/this.synth.fps // ms - if(this.synth.update) { - try { this.synth.update(dt) } catch (e) { console.log(error) } + /** + Get the extent, content, and (if there is a token) type of the + token before `this.pos`. + */ + tokenBefore(types) { + let token = language.syntaxTree(this.state).resolveInner(this.pos, -1); + while (token && types.indexOf(token.name) < 0) + token = token.parent; + return token ? { from: token.from, to: this.pos, + text: this.state.sliceDoc(token.from, this.pos), + type: token.type } : null; } - - this.sandbox.set('time', this.synth.time += dt * 0.001 * this.synth.speed) - this.timeSinceLastUpdate += dt - if(!this.synth.fps || this.timeSinceLastUpdate >= 1000/this.synth.fps) { - // console.log(1000/this.timeSinceLastUpdate) - this.synth.stats.fps = Math.ceil(1000/this.timeSinceLastUpdate) - // console.log(this.synth.speed, this.synth.time) - for (let i = 0; i < this.s.length; i++) { - this.s[i].tick(this.synth.time) - } - // console.log(this.canvas.width, this.canvas.height) - for (let i = 0; i < this.o.length; i++) { - this.o[i].tick({ - time: this.synth.time, - mouse: this.synth.mouse, - bpm: this.synth.bpm, - resolution: [this.canvas.width, this.canvas.height] - }) - } - if (this.isRenderingAll) { - this.renderAll({ - tex0: this.o[0].getCurrent(), - tex1: this.o[1].getCurrent(), - tex2: this.o[2].getCurrent(), - tex3: this.o[3].getCurrent(), - resolution: [this.canvas.width, this.canvas.height] - }) - } else { - - this.renderFbo({ - tex0: this.output.getCurrent(), - resolution: [this.canvas.width, this.canvas.height] - }) - } - this.timeSinceLastUpdate = 0 + /** + Get the match of the given expression directly before the + cursor. + */ + matchBefore(expr) { + let line = this.state.doc.lineAt(this.pos); + let start = Math.max(line.from, this.pos - 250); + let str = line.text.slice(start - line.from, this.pos - line.from); + let found = str.search(ensureAnchor(expr, false)); + return found < 0 ? null : { from: start + found, to: this.pos, text: str.slice(found) }; } - if(this.saveFrame === true) { - this.canvasToImage() - this.saveFrame = false + /** + Yields true when the query has been aborted. Can be useful in + asynchronous queries to avoid doing work that will be ignored. + */ + get aborted() { return this.abortListeners == null; } + /** + Allows you to register abort handlers, which will be called when + the query is + [aborted](https://codemirror.net/6/docs/ref/#autocomplete.CompletionContext.aborted). + */ + addEventListener(type, listener) { + if (type == "abort" && this.abortListeners) + this.abortListeners.push(listener); } - // this.regl.poll() - } - - } - -module.exports = HydraRenderer - -},{"./src/eval-sandbox.js":10,"./src/generator-factory.js":13,"./src/hydra-source.js":17,"./src/lib/array-utils.js":18,"./src/lib/audio.js":19,"./src/lib/mouse.js":22,"./src/lib/video-recorder.js":25,"./src/output.js":27,"raf-loop":113,"regl":115}],9:[function(require,module,exports){ -const Synth = require('./hydra-synth.js') -//const ShaderGenerator = require('./shader-generator.js') - -module.exports = Synth - -},{"./hydra-synth.js":8}],10:[function(require,module,exports){ -// handles code evaluation and attaching relevant objects to global and evaluation contexts - -const Sandbox = require('./lib/sandbox.js') -const ArrayUtils = require('./lib/array-utils.js') - -class EvalSandbox { - constructor(parent, makeGlobal, userProps = []) { - this.makeGlobal = makeGlobal - this.sandbox = Sandbox(parent) - this.parent = parent - var properties = Object.keys(parent) - properties.forEach((property) => this.add(property)) - this.userProps = userProps - } - - add(name) { - if(this.makeGlobal) window[name] = this.parent[name] - this.sandbox.addToContext(name, `parent.${name}`) - } - -// sets on window as well as synth object if global (not needed for objects, which can be set directly) - - set(property, value) { - if(this.makeGlobal) { - window[property] = value - } - this.parent[property] = value - } - - tick() { - if(this.makeGlobal) { - this.userProps.forEach((property) => { - this.parent[property] = window[property] - }) - // this.parent.speed = window.speed - } else { - +function toSet(chars) { + let flat = Object.keys(chars).join(""); + let words = /\w/.test(flat); + if (words) + flat = flat.replace(/\w/g, ""); + return `[${words ? "\\w" : ""}${flat.replace(/[^\w\s]/g, "\\$&")}]`; +} +function prefixMatch(options) { + let first = Object.create(null), rest = Object.create(null); + for (let { label } of options) { + first[label[0]] = true; + for (let i = 1; i < label.length; i++) + rest[label[i]] = true; } - } - - eval(code) { - this.sandbox.eval(code) - } + let source = toSet(first) + toSet(rest) + "*$"; + return [new RegExp("^" + source), new RegExp(source)]; } - -module.exports = EvalSandbox - -},{"./lib/array-utils.js":18,"./lib/sandbox.js":23}],11:[function(require,module,exports){ -const arrayUtils = require('./lib/array-utils.js') - -// [WIP] how to treat different dimensions (?) -const DEFAULT_CONVERSIONS = { - float: { - 'vec4': { name: 'sum', args: [[1, 1, 1, 1]] }, - 'vec2': { name: 'sum', args: [[1, 1]] } - } +/** +Given a a fixed array of options, return an autocompleter that +completes them. +*/ +function completeFromList(list) { + let options = list.map(o => typeof o == "string" ? { label: o } : o); + let [span, match] = options.every(o => /^\w+$/.test(o.label)) ? [/\w*$/, /\w+$/] : prefixMatch(options); + return (context) => { + let token = context.matchBefore(match); + return token || context.explicit ? { from: token ? token.from : context.pos, options, span } : null; + }; } - -function fillArrayWithDefaults(arr, len) { - // fill the array with default values if it's too short - while (arr.length < len) { - if (arr.length === 3) { // push a 1 as the default for .a in vec4 - arr.push(1.0) - } else { - arr.push(0.0) +/** +Wrap the given completion source so that it will only fire when the +cursor is in a syntax node with one of the given names. +*/ +function ifIn(nodes, source) { + return (context) => { + for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) + if (nodes.indexOf(pos.name) > -1) + return source(context); + return null; + }; +} +/** +Wrap the given completion source so that it will not fire when the +cursor is in a syntax node with one of the given names. +*/ +function ifNotIn(nodes, source) { + return (context) => { + for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) + if (nodes.indexOf(pos.name) > -1) + return null; + return source(context); + }; +} +class Option { + constructor(completion, source, match) { + this.completion = completion; + this.source = source; + this.match = match; } - } - return arr.slice(0, len) } - -const ensure_decimal_dot = (val) => { - val = val.toString() - if (val.indexOf('.') < 0) { - val += '.' - } - return val +function cur(state) { return state.selection.main.head; } +// Make sure the given regexp has a $ at its end and, if `start` is +// true, a ^ at its start. +function ensureAnchor(expr, start) { + var _a; + let { source } = expr; + let addStart = start && source[0] != "^", addEnd = source[source.length - 1] != "$"; + if (!addStart && !addEnd) + return expr; + return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : (expr.ignoreCase ? "i" : "")); } - - - -module.exports = function formatArguments(transform, startIndex, synthContext) { - const defaultArgs = transform.transform.inputs - const userArgs = transform.userArgs - const { generators } = transform.synth - const { src } = generators // depends on synth having src() function - return defaultArgs.map((input, index) => { - const typedArg = { - value: input.default, - type: input.type, // - isUniform: false, - name: input.name, - vecLen: 0 - // generateGlsl: null // function for creating glsl +/** +This annotation is added to transactions that are produced by +picking a completion. +*/ +const pickedCompletion = state.Annotation.define(); +function applyCompletion(view, option) { + let apply = option.completion.apply || option.completion.label; + let result = option.source; + if (typeof apply == "string") { + view.dispatch({ + changes: { from: result.from, to: result.to, insert: apply }, + selection: { anchor: result.from + apply.length }, + userEvent: "input.complete", + annotations: pickedCompletion.of(option.completion) + }); } - - if (typedArg.type === 'float') typedArg.value = ensure_decimal_dot(input.default) - if (input.type.startsWith('vec')) { - try { - typedArg.vecLen = Number.parseInt(input.type.substr(3)) - } catch (e) { - console.log(`Error determining length of vector input type ${input.type} (${input.name})`) - } + else { + apply(view, option.completion, result.from, result.to); } +} +const SourceCache = new WeakMap(); +function asSource(source) { + if (!Array.isArray(source)) + return source; + let known = SourceCache.get(source); + if (!known) + SourceCache.set(source, known = completeFromList(source)); + return known; +} - // if user has input something for this argument - if (userArgs.length > index) { - typedArg.value = userArgs[index] - // do something if a composite or transform - - if (typeof userArgs[index] === 'function') { - // if (typedArg.vecLen > 0) { // expected input is a vector, not a scalar - // typedArg.value = (context, props, batchId) => (fillArrayWithDefaults(userArgs[index](props), typedArg.vecLen)) - // } else { - typedArg.value = (context, props, batchId) => { - try { - return userArgs[index](props) - } catch (e) { - console.log('ERROR', e) - return input.default - } +// A pattern matcher for fuzzy completion matching. Create an instance +// once for a pattern, and then use that to match any number of +// completions. +class FuzzyMatcher { + constructor(pattern) { + this.pattern = pattern; + this.chars = []; + this.folded = []; + // Buffers reused by calls to `match` to track matched character + // positions. + this.any = []; + this.precise = []; + this.byWord = []; + for (let p = 0; p < pattern.length;) { + let char = text.codePointAt(pattern, p), size = text.codePointSize(char); + this.chars.push(char); + let part = pattern.slice(p, p + size), upper = part.toUpperCase(); + this.folded.push(text.codePointAt(upper == part ? part.toLowerCase() : upper, 0)); + p += size; } - // } - - typedArg.isUniform = true - } else if (userArgs[index].constructor === Array) { - // if (typedArg.vecLen > 0) { // expected input is a vector, not a scalar - // typedArg.isUniform = true - // typedArg.value = fillArrayWithDefaults(typedArg.value, typedArg.vecLen) - // } else { - // console.log("is Array") - typedArg.value = (context, props, batchId) => arrayUtils.getValue(userArgs[index])(props) - typedArg.isUniform = true - // } - } + this.astral = pattern.length != this.chars.length; } - - if (startIndex < 0) { - } else { - if (typedArg.value && typedArg.value.transforms) { - const final_transform = typedArg.value.transforms[typedArg.value.transforms.length - 1] - - if (final_transform.transform.glsl_return_type !== input.type) { - const defaults = DEFAULT_CONVERSIONS[input.type] - if (typeof defaults !== 'undefined') { - const default_def = defaults[final_transform.transform.glsl_return_type] - if (typeof default_def !== 'undefined') { - const { name, args } = default_def - typedArg.value = typedArg.value[name](...args) + // Matches a given word (completion) against the pattern (input). + // Will return null for no match, and otherwise an array that starts + // with the match score, followed by any number of `from, to` pairs + // indicating the matched parts of `word`. + // + // The score is a number that is more negative the worse the match + // is. See `Penalty` above. + match(word) { + if (this.pattern.length == 0) + return [0]; + if (word.length < this.pattern.length) + return null; + let { chars, folded, any, precise, byWord } = this; + // For single-character queries, only match when they occur right + // at the start + if (chars.length == 1) { + let first = text.codePointAt(word, 0); + return first == chars[0] ? [0, 0, text.codePointSize(first)] + : first == folded[0] ? [-200 /* CaseFold */, 0, text.codePointSize(first)] : null; + } + let direct = word.indexOf(this.pattern); + if (direct == 0) + return [0, 0, this.pattern.length]; + let len = chars.length, anyTo = 0; + if (direct < 0) { + for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) { + let next = text.codePointAt(word, i); + if (next == chars[anyTo] || next == folded[anyTo]) + any[anyTo++] = i; + i += text.codePointSize(next); } - } + // No match, exit immediately + if (anyTo < len) + return null; } - - typedArg.isUniform = false - } else if (typedArg.type === 'float' && typeof typedArg.value === 'number') { - typedArg.value = ensure_decimal_dot(typedArg.value) - } else if (typedArg.type.startsWith('vec') && typeof typedArg.value === 'object' && Array.isArray(typedArg.value)) { - typedArg.isUniform = false - typedArg.value = `${typedArg.type}(${typedArg.value.map(ensure_decimal_dot).join(', ')})` - } else if (input.type === 'sampler2D') { - // typedArg.tex = typedArg.value - var x = typedArg.value - typedArg.value = () => (x.getTexture()) - typedArg.isUniform = true - } else { - // if passing in a texture reference, when function asks for vec4, convert to vec4 - if (typedArg.value.getTexture && input.type === 'vec4') { - var x1 = typedArg.value - typedArg.value = src(x1) - typedArg.isUniform = false + // This tracks the extent of the precise (non-folded, not + // necessarily adjacent) match + let preciseTo = 0; + // Tracks whether there is a match that hits only characters that + // appear to be starting words. `byWordFolded` is set to true when + // a case folded character is encountered in such a match + let byWordTo = 0, byWordFolded = false; + // If we've found a partial adjacent match, these track its state + let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1; + let hasLower = /[a-z]/.test(word), wordAdjacent = true; + // Go over the option's text, scanning for the various kinds of matches + for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* NonWord */; i < e && byWordTo < len;) { + let next = text.codePointAt(word, i); + if (direct < 0) { + if (preciseTo < len && next == chars[preciseTo]) + precise[preciseTo++] = i; + if (adjacentTo < len) { + if (next == chars[adjacentTo] || next == folded[adjacentTo]) { + if (adjacentTo == 0) + adjacentStart = i; + adjacentEnd = i + 1; + adjacentTo++; + } + else { + adjacentTo = 0; + } + } + } + let ch, type = next < 0xff + ? (next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 /* Lower */ : next >= 65 && next <= 90 ? 1 /* Upper */ : 0 /* NonWord */) + : ((ch = text.fromCodePoint(next)) != ch.toLowerCase() ? 1 /* Upper */ : ch != ch.toUpperCase() ? 2 /* Lower */ : 0 /* NonWord */); + if (!i || type == 1 /* Upper */ && hasLower || prevType == 0 /* NonWord */ && type != 0 /* NonWord */) { + if (chars[byWordTo] == next || (folded[byWordTo] == next && (byWordFolded = true))) + byWord[byWordTo++] = i; + else if (byWord.length) + wordAdjacent = false; + } + prevType = type; + i += text.codePointSize(next); } - } - - // add tp uniform array if is a function that will pass in a different value on each render frame, - // or a texture/ external source - - if (typedArg.isUniform) { - typedArg.name += startIndex - // shaderParams.uniforms.push(typedArg) - } + if (byWordTo == len && byWord[0] == 0 && wordAdjacent) + return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0), byWord, word); + if (adjacentTo == len && adjacentStart == 0) + return [-200 /* CaseFold */ - word.length, 0, adjacentEnd]; + if (direct > -1) + return [-700 /* NotStart */ - word.length, direct, direct + this.pattern.length]; + if (adjacentTo == len) + return [-200 /* CaseFold */ + -700 /* NotStart */ - word.length, adjacentStart, adjacentEnd]; + if (byWordTo == len) + return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0) + -700 /* NotStart */ + + (wordAdjacent ? 0 : -1100 /* Gap */), byWord, word); + return chars.length == 2 ? null : this.result((any[0] ? -700 /* NotStart */ : 0) + -200 /* CaseFold */ + -1100 /* Gap */, any, word); + } + result(score, positions, word) { + let result = [score - word.length], i = 1; + for (let pos of positions) { + let to = pos + (this.astral ? text.codePointSize(text.codePointAt(word, pos)) : 1); + if (i > 1 && result[i - 1] == pos) + result[i - 1] = to; + else { + result[i++] = pos; + result[i++] = to; + } + } + return result; } - return typedArg - }) } - -},{"./lib/array-utils.js":18}],12:[function(require,module,exports){ -const formatArguments = require('./format-arguments.js') - -// Add extra functionality to Array.prototype for generating sequences in time -const arrayUtils = require('./lib/array-utils.js') - - - -// converts a tree of javascript functions to a shader -module.exports = function (transforms) { - var shaderParams = { - uniforms: [], // list of uniforms used in shader - glslFunctions: [], // list of functions used in shader - fragColor: '' +const completionConfig = state.Facet.define({ + combine(configs) { + return state.combineConfig(configs, { + activateOnTyping: true, + override: null, + maxRenderedOptions: 100, + defaultKeymap: true, + optionClass: () => "", + aboveCursor: false, + icons: true, + addToOptions: [] + }, { + defaultKeymap: (a, b) => a && b, + icons: (a, b) => a && b, + optionClass: (a, b) => c => joinClass(a(c), b(c)), + addToOptions: (a, b) => a.concat(b) + }); } - - var gen = generateGlsl(transforms, shaderParams)('st') - shaderParams.fragColor = gen - // remove uniforms with duplicate names - let uniforms = {} - shaderParams.uniforms.forEach((uniform) => uniforms[uniform.name] = uniform) - shaderParams.uniforms = Object.values(uniforms) - return shaderParams - +}); +function joinClass(a, b) { + return a ? b ? a + " " + b : a : b; } - -// recursive function for generating shader string from object containing functions and user arguments. Order of functions in string depends on type of function -// to do: improve variable names -function generateGlsl (transforms, shaderParams) { - // transform function that outputs a shader string corresponding to gl_FragColor - var fragColor = () => '' - // var uniforms = [] - // var glslFunctions = [] - transforms.forEach((transform) => { - var inputs = formatArguments(transform, shaderParams.uniforms.length) - inputs.forEach((input) => { - if(input.isUniform) shaderParams.uniforms.push(input) - }) - - // add new glsl function to running list of functions - if(!contains(transform, shaderParams.glslFunctions)) shaderParams.glslFunctions.push(transform) - - // current function for generating frag color shader code - var f0 = fragColor - if (transform.transform.type === 'src') { - fragColor = (uv) => `${shaderString(uv, transform.name, inputs, shaderParams)}` - } else if (transform.transform.type === 'coord') { - fragColor = (uv) => `${f0(`${shaderString(uv, transform.name, inputs, shaderParams)}`)}` - } else if (transform.transform.type === 'color') { - fragColor = (uv) => `${shaderString(`${f0(uv)}`, transform.name, inputs, shaderParams)}` - } else if (transform.transform.type === 'combine') { - // combining two generated shader strings (i.e. for blend, mult, add funtions) - var f1 = inputs[0].value && inputs[0].value.transforms ? - (uv) => `${generateGlsl(inputs[0].value.transforms, shaderParams)(uv)}` : - (inputs[0].isUniform ? () => inputs[0].name : () => inputs[0].value) - fragColor = (uv) => `${shaderString(`${f0(uv)}, ${f1(uv)}`, transform.name, inputs.slice(1), shaderParams)}` - } else if (transform.transform.type === 'combineCoord') { - // combining two generated shader strings (i.e. for modulate functions) - var f1 = inputs[0].value && inputs[0].value.transforms ? - (uv) => `${generateGlsl(inputs[0].value.transforms, shaderParams)(uv)}` : - (inputs[0].isUniform ? () => inputs[0].name : () => inputs[0].value) - fragColor = (uv) => `${f0(`${shaderString(`${uv}, ${f1(uv)}`, transform.name, inputs.slice(1), shaderParams)}`)}` - - - } - }) -// console.log(fragColor) - // break; - return fragColor +function optionContent(config) { + let content = config.addToOptions.slice(); + if (config.icons) + content.push({ + render(completion) { + let icon = document.createElement("div"); + icon.classList.add("cm-completionIcon"); + if (completion.type) + icon.classList.add(...completion.type.split(/\s+/g).map(cls => "cm-completionIcon-" + cls)); + icon.setAttribute("aria-hidden", "true"); + return icon; + }, + position: 20 + }); + content.push({ + render(completion, _s, match) { + let labelElt = document.createElement("span"); + labelElt.className = "cm-completionLabel"; + let { label } = completion, off = 0; + for (let j = 1; j < match.length;) { + let from = match[j++], to = match[j++]; + if (from > off) + labelElt.appendChild(document.createTextNode(label.slice(off, from))); + let span = labelElt.appendChild(document.createElement("span")); + span.appendChild(document.createTextNode(label.slice(from, to))); + span.className = "cm-completionMatchedText"; + off = to; + } + if (off < label.length) + labelElt.appendChild(document.createTextNode(label.slice(off))); + return labelElt; + }, + position: 50 + }, { + render(completion) { + if (!completion.detail) + return null; + let detailElt = document.createElement("span"); + detailElt.className = "cm-completionDetail"; + detailElt.textContent = completion.detail; + return detailElt; + }, + position: 80 + }); + return content.sort((a, b) => a.position - b.position).map(a => a.render); } - -// assembles a shader string containing the arguments and the function name, i.e. 'osc(uv, frequency)' -function shaderString (uv, method, inputs, shaderParams) { - const str = inputs.map((input) => { - if (input.isUniform) { - return input.name - } else if (input.value && input.value.transforms) { - // this by definition needs to be a generator, hence we start with 'st' as the initial value for generating the glsl fragment - return `${generateGlsl(input.value.transforms, shaderParams)('st')}` +function createInfoDialog(option, view$1) { + let dom = document.createElement("div"); + dom.className = "cm-tooltip cm-completionInfo"; + let { info } = option.completion; + if (typeof info == "string") { + dom.textContent = info; } - return input.value - }).reduce((p, c) => `${p}, ${c}`, '') - - return `${method}(${uv}${str})` -} - -// merge two arrays and remove duplicates -function mergeArrays (a, b) { - return a.concat(b.filter(function (item) { - return a.indexOf(item) < 0; - })) + else { + let content = info(option.completion); + if (content.then) + content.then(node => dom.appendChild(node), e => view.logException(view$1.state, e, "completion info")); + else + dom.appendChild(content); + } + return dom; } - -// check whether array -function contains(object, arr) { - for(var i = 0; i < arr.length; i++){ - if(object.name == arr[i].name) return true - } - return false +function rangeAroundSelected(total, selected, max) { + if (total <= max) + return { from: 0, to: total }; + if (selected <= (total >> 1)) { + let off = Math.floor(selected / max); + return { from: off * max, to: (off + 1) * max }; + } + let off = Math.floor((total - selected) / max); + return { from: total - (off + 1) * max, to: total - off * max }; } - - - - -},{"./format-arguments.js":11,"./lib/array-utils.js":18}],13:[function(require,module,exports){ -const GlslSource = require('./glsl-source.js') - -class GeneratorFactory { - constructor ({ - defaultUniforms, - defaultOutput, - extendTransforms = [], - changeListener = (() => {}) - } = {} - ) { - this.defaultOutput = defaultOutput - this.defaultUniforms = defaultUniforms - this.changeListener = changeListener - this.extendTransforms = extendTransforms - this.generators = {} - this.init() - } - init () { - this.glslTransforms = {} - this.generators = Object.entries(this.generators).reduce((prev, [method, transform]) => { - this.changeListener({type: 'remove', synth: this, method}) - return prev - }, {}) - - this.sourceClass = (() => { - return class extends GlslSource { - } - })() - - let functions = require('./glsl/glsl-functions.js')() - - // add user definied transforms - if (Array.isArray(this.extendTransforms)) { - functions.concat(this.extendTransforms) - } else if (typeof this.extendTransforms === 'object' && this.extendTransforms.type) { - functions.push(this.extendTransforms) +class CompletionTooltip { + constructor(view, stateField) { + this.view = view; + this.stateField = stateField; + this.info = null; + this.placeInfo = { + read: () => this.measureInfo(), + write: (pos) => this.positionInfo(pos), + key: this + }; + let cState = view.state.field(stateField); + let { options, selected } = cState.open; + let config = view.state.facet(completionConfig); + this.optionContent = optionContent(config); + this.optionClass = config.optionClass; + this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions); + this.dom = document.createElement("div"); + this.dom.className = "cm-tooltip-autocomplete"; + this.dom.addEventListener("mousedown", (e) => { + for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) { + if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) { + applyCompletion(view, options[+match[1]]); + e.preventDefault(); + return; + } + } + }); + this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range)); + this.list.addEventListener("scroll", () => { + if (this.info) + this.view.requestMeasure(this.placeInfo); + }); } - - return functions.map((transform) => this.setFunction(transform)) - } - - _addMethod (method, transform) { - const self = this - this.glslTransforms[method] = transform - if (transform.type === 'src') { - const func = (...args) => new this.sourceClass({ - name: method, - transform: transform, - userArgs: args, - defaultOutput: this.defaultOutput, - defaultUniforms: this.defaultUniforms, - synth: self - }) - this.generators[method] = func - this.changeListener({type: 'add', synth: this, method}) - return func - } else { - this.sourceClass.prototype[method] = function (...args) { - this.transforms.push({name: method, transform: transform, userArgs: args, synth: self}) - return this - } + mount() { this.updateSel(); } + update(update) { + if (update.state.field(this.stateField) != update.startState.field(this.stateField)) + this.updateSel(); + } + positioned() { + if (this.info) + this.view.requestMeasure(this.placeInfo); + } + updateSel() { + let cState = this.view.state.field(this.stateField), open = cState.open; + if (open.selected < this.range.from || open.selected >= this.range.to) { + this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions); + this.list.remove(); + this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range)); + this.list.addEventListener("scroll", () => { + if (this.info) + this.view.requestMeasure(this.placeInfo); + }); + } + if (this.updateSelectedOption(open.selected)) { + if (this.info) { + this.info.remove(); + this.info = null; + } + let option = open.options[open.selected]; + if (option.completion.info) { + this.info = this.dom.appendChild(createInfoDialog(option, this.view)); + this.view.requestMeasure(this.placeInfo); + } + } + } + updateSelectedOption(selected) { + let set = null; + for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) { + if (i == selected) { + if (!opt.hasAttribute("aria-selected")) { + opt.setAttribute("aria-selected", "true"); + set = opt; + } + } + else { + if (opt.hasAttribute("aria-selected")) + opt.removeAttribute("aria-selected"); + } + } + if (set) + scrollIntoView(this.list, set); + return set; + } + measureInfo() { + let sel = this.dom.querySelector("[aria-selected]"); + if (!sel || !this.info) + return null; + let listRect = this.dom.getBoundingClientRect(); + let infoRect = this.info.getBoundingClientRect(); + let selRect = sel.getBoundingClientRect(); + if (selRect.top > Math.min(innerHeight, listRect.bottom) - 10 || selRect.bottom < Math.max(0, listRect.top) + 10) + return null; + let top = Math.max(0, Math.min(selRect.top, innerHeight - infoRect.height)) - listRect.top; + let left = this.view.textDirection == view.Direction.RTL; + let spaceLeft = listRect.left, spaceRight = innerWidth - listRect.right; + if (left && spaceLeft < Math.min(infoRect.width, spaceRight)) + left = false; + else if (!left && spaceRight < Math.min(infoRect.width, spaceLeft)) + left = true; + return { top, left }; + } + positionInfo(pos) { + if (this.info) { + this.info.style.top = (pos ? pos.top : -1e6) + "px"; + if (pos) { + this.info.classList.toggle("cm-completionInfo-left", pos.left); + this.info.classList.toggle("cm-completionInfo-right", !pos.left); + } + } + } + createListBox(options, id, range) { + const ul = document.createElement("ul"); + ul.id = id; + ul.setAttribute("role", "listbox"); + for (let i = range.from; i < range.to; i++) { + let { completion, match } = options[i]; + const li = ul.appendChild(document.createElement("li")); + li.id = id + "-" + i; + li.setAttribute("role", "option"); + let cls = this.optionClass(completion); + if (cls) + li.className = cls; + for (let source of this.optionContent) { + let node = source(completion, this.view.state, match); + if (node) + li.appendChild(node); + } + } + if (range.from) + ul.classList.add("cm-completionListIncompleteTop"); + if (range.to < options.length) + ul.classList.add("cm-completionListIncompleteBottom"); + return ul; } - return undefined - } - - setFunction(obj) { - var processedGlsl = processGlsl(obj) - if(processedGlsl) this._addMethod(obj.name, processedGlsl) - } -} - -const typeLookup = { - 'src': { - returnType: 'vec4', - args: ['vec2 _st'] - }, - 'coord': { - returnType: 'vec2', - args: ['vec2 _st'] - }, - 'color': { - returnType: 'vec4', - args: ['vec4 _c0'] - }, - 'combine': { - returnType: 'vec4', - args: ['vec4 _c0', 'vec4 _c1'] - }, - 'combineCoord': { - returnType: 'vec2', - args: ['vec2 _st', 'vec4 _c0'] - } -} -// expects glsl of format -// { -// name: 'osc', // name that will be used to access function as well as within glsl -// type: 'src', // can be src: vec4(vec2 _st), coord: vec2(vec2 _st), color: vec4(vec4 _c0), combine: vec4(vec4 _c0, vec4 _c1), combineCoord: vec2(vec2 _st, vec4 _c0) -// inputs: [ -// { -// name: 'freq', -// type: 'float', // 'float' //, 'texture', 'vec4' -// default: 0.2 -// }, -// { -// name: 'sync', -// type: 'float', -// default: 0.1 -// }, -// { -// name: 'offset', -// type: 'float', -// default: 0.0 -// } -// ], - // glsl: ` - // vec2 st = _st; - // float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; - // float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; - // float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; - // return vec4(r, g, b, 1.0); - // ` -// } - -// // generates glsl function: -// `vec4 osc(vec2 _st, float freq, float sync, float offset){ -// vec2 st = _st; -// float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; -// float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; -// float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; -// return vec4(r, g, b, 1.0); -// }` - -function processGlsl(obj) { - let t = typeLookup[obj.type] - if(t) { - let baseArgs = t.args.map((arg) => arg).join(", ") - // @todo: make sure this works for all input types, add validation - let customArgs = obj.inputs.map((input) => `${input.type} ${input.name}`).join(', ') - let args = `${baseArgs}${customArgs.length > 0 ? ', '+ customArgs: ''}` -// console.log('args are ', args) - - let glslFunction = -` - ${t.returnType} ${obj.name}(${args}) { - ${obj.glsl} - } -` - - // add extra input to beginning for backward combatibility @todo update compiler so this is no longer necessary - if(obj.type === 'combine' || obj.type === 'combineCoord') obj.inputs.unshift({ - name: 'color', - type: 'vec4' - }) - return Object.assign({}, obj, { glsl: glslFunction}) - } else { - console.warn(`type ${obj.type} not recognized`, obj) - } - } - -module.exports = GeneratorFactory - -},{"./glsl-source.js":14,"./glsl/glsl-functions.js":15}],14:[function(require,module,exports){ -const generateGlsl = require('./generate-glsl.js') -// const formatArguments = require('./glsl-utils.js').formatArguments - -// const glslTransforms = require('./glsl/composable-glsl-functions.js') -const utilityGlsl = require('./glsl/utility-functions.js') - -var GlslSource = function (obj) { - this.transforms = [] - this.transforms.push(obj) - this.defaultOutput = obj.defaultOutput - this.synth = obj.synth - this.type = 'GlslSource' - this.defaultUniforms = obj.defaultUniforms - return this +// We allocate a new function instance every time the completion +// changes to force redrawing/repositioning of the tooltip +function completionTooltip(stateField) { + return (view) => new CompletionTooltip(view, stateField); } - -GlslSource.prototype.addTransform = function (obj) { - this.transforms.push(obj) +function scrollIntoView(container, element) { + let parent = container.getBoundingClientRect(); + let self = element.getBoundingClientRect(); + if (self.top < parent.top) + container.scrollTop -= parent.top - self.top; + else if (self.bottom > parent.bottom) + container.scrollTop += self.bottom - parent.bottom; } -GlslSource.prototype.out = function (_output) { - var output = _output || this.defaultOutput - var glsl = this.glsl(output) - this.synth.currentFunctions = [] - // output.renderPasses(glsl) - if(output) try{ - output.render(glsl) - } catch (error) { - console.log('shader could not compile', error) - } +const MaxOptions = 300; +// Used to pick a preferred option when two options with the same +// label occur in the result. +function score(option) { + return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + + (option.type ? 1 : 0); } - -GlslSource.prototype.glsl = function () { - //var output = _output || this.defaultOutput - var self = this - // uniforms included in all shaders -// this.defaultUniforms = output.uniforms - var passes = [] - var transforms = [] -// console.log('output', output) - this.transforms.forEach((transform) => { - if(transform.transform.type === 'renderpass'){ - // if (transforms.length > 0) passes.push(this.compile(transforms, output)) - // transforms = [] - // var uniforms = {} - // const inputs = formatArguments(transform, -1) - // inputs.forEach((uniform) => { uniforms[uniform.name] = uniform.value }) - // - // passes.push({ - // frag: transform.transform.frag, - // uniforms: Object.assign({}, self.defaultUniforms, uniforms) - // }) - // transforms.push({name: 'prev', transform: glslTransforms['prev'], synth: this.synth}) - console.warn('no support for renderpass') - } else { - transforms.push(transform) +function sortOptions(active, state) { + let options = [], i = 0; + for (let a of active) + if (a.hasResult()) { + if (a.result.filter === false) { + for (let option of a.result.options) + options.push(new Option(option, a, [1e9 - i++])); + } + else { + let matcher = new FuzzyMatcher(state.sliceDoc(a.from, a.to)), match; + for (let option of a.result.options) + if (match = matcher.match(option.label)) { + if (option.boost != null) + match[0] += option.boost; + options.push(new Option(option, a, match)); + } + } + } + options.sort(cmpOption); + let result = [], prev = null; + for (let opt of options.sort(cmpOption)) { + if (result.length == MaxOptions) + break; + if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail || + prev.type != opt.completion.type || prev.apply != opt.completion.apply) + result.push(opt); + else if (score(opt.completion) > score(prev)) + result[result.length - 1] = opt; + prev = opt.completion; } - }) - - if (transforms.length > 0) passes.push(this.compile(transforms)) - - return passes + return result; } - -GlslSource.prototype.compile = function (transforms) { - var shaderInfo = generateGlsl(transforms, this.synth) - var uniforms = {} - shaderInfo.uniforms.forEach((uniform) => { uniforms[uniform.name] = uniform.value }) - - var frag = ` - precision ${this.defaultOutput.precision} float; - ${Object.values(shaderInfo.uniforms).map((uniform) => { - let type = uniform.type - switch (uniform.type) { - case 'texture': - type = 'sampler2D' - break +class CompletionDialog { + constructor(options, attrs, tooltip, timestamp, selected) { + this.options = options; + this.attrs = attrs; + this.tooltip = tooltip; + this.timestamp = timestamp; + this.selected = selected; + } + setSelected(selected, id) { + return selected == this.selected || selected >= this.options.length ? this + : new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected); + } + static build(active, state, id, prev, conf) { + let options = sortOptions(active, state); + if (!options.length) + return null; + let selected = 0; + if (prev && prev.selected) { + let selectedValue = prev.options[prev.selected].completion; + for (let i = 0; i < options.length && !selected; i++) { + if (options[i].completion == selectedValue) + selected = i; + } + } + return new CompletionDialog(options, makeAttrs(id, selected), { + pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8), + create: completionTooltip(completionState), + above: conf.aboveCursor, + }, prev ? prev.timestamp : Date.now(), selected); + } + map(changes) { + return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected); } - return ` - uniform ${type} ${uniform.name};` - }).join('')} - uniform float time; - uniform vec2 resolution; - varying vec2 uv; - uniform sampler2D prevBuffer; - - ${Object.values(utilityGlsl).map((transform) => { - // console.log(transform.glsl) - return ` - ${transform.glsl} - ` - }).join('')} - - ${shaderInfo.glslFunctions.map((transform) => { - return ` - ${transform.transform.glsl} - ` - }).join('')} - - void main () { - vec4 c = vec4(1, 0, 0, 1); - vec2 st = gl_FragCoord.xy/resolution.xy; - gl_FragColor = ${shaderInfo.fragColor}; - } - ` - - return { - frag: frag, - uniforms: Object.assign({}, this.defaultUniforms, uniforms) - } - } - -module.exports = GlslSource - -},{"./generate-glsl.js":12,"./glsl/utility-functions.js":16}],15:[function(require,module,exports){ -/* -Format for adding functions to hydra. For each entry in this file, hydra automatically generates a glsl function and javascript function with the same name. You can also ass functions dynamically using setFunction(object). - -{ - name: 'osc', // name that will be used to access function in js as well as in glsl - type: 'src', // can be 'src', 'color', 'combine', 'combineCoords'. see below for more info - inputs: [ - { - name: 'freq', - type: 'float', - default: 0.2 - }, - { - name: 'sync', - type: 'float', - default: 0.1 - }, - { - name: 'offset', - type: 'float', - default: 0.0 +class CompletionState { + constructor(active, id, open) { + this.active = active; + this.id = id; + this.open = open; } - ], - glsl: ` - vec2 st = _st; - float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; - float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; - float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; - return vec4(r, g, b, 1.0); - ` + static start() { + return new CompletionState(none, "cm-ac-" + Math.floor(Math.random() * 2e6).toString(36), null); + } + update(tr) { + let { state } = tr, conf = state.facet(completionConfig); + let sources = conf.override || + state.languageDataAt("autocomplete", cur(state)).map(asSource); + let active = sources.map(source => { + let value = this.active.find(s => s.source == source) || + new ActiveSource(source, this.active.some(a => a.state != 0 /* Inactive */) ? 1 /* Pending */ : 0 /* Inactive */); + return value.update(tr, conf); + }); + if (active.length == this.active.length && active.every((a, i) => a == this.active[i])) + active = this.active; + let open = tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || + !sameResults(active, this.active) ? CompletionDialog.build(active, state, this.id, this.open, conf) + : this.open && tr.docChanged ? this.open.map(tr.changes) : this.open; + if (!open && active.every(a => a.state != 1 /* Pending */) && active.some(a => a.hasResult())) + active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* Inactive */) : a); + for (let effect of tr.effects) + if (effect.is(setSelectedEffect)) + open = open && open.setSelected(effect.value, this.id); + return active == this.active && open == this.open ? this : new CompletionState(active, this.id, open); + } + get tooltip() { return this.open ? this.open.tooltip : null; } + get attrs() { return this.open ? this.open.attrs : baseAttrs; } } - -// The above code generates the glsl function: -`vec4 osc(vec2 _st, float freq, float sync, float offset){ - vec2 st = _st; - float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; - float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; - float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; - return vec4(r, g, b, 1.0); -}` - - -Types and default arguments for hydra functions. -The value in the 'type' field lets the parser know which type the function will be returned as well as default arguments. - -const types = { - 'src': { - returnType: 'vec4', - args: ['vec2 _st'] - }, - 'coord': { - returnType: 'vec2', - args: ['vec2 _st'] - }, - 'color': { - returnType: 'vec4', - args: ['vec4 _c0'] - }, - 'combine': { - returnType: 'vec4', - args: ['vec4 _c0', 'vec4 _c1'] - }, - 'combineCoord': { - returnType: 'vec2', - args: ['vec2 _st', 'vec4 _c0'] - } +function sameResults(a, b) { + if (a == b) + return true; + for (let iA = 0, iB = 0;;) { + while (iA < a.length && !a[iA].hasResult) + iA++; + while (iB < b.length && !b[iB].hasResult) + iB++; + let endA = iA == a.length, endB = iB == b.length; + if (endA || endB) + return endA == endB; + if (a[iA++].result != b[iB++].result) + return false; + } } - -*/ - -module.exports = () => [ - { - name: 'noise', - type: 'src', - inputs: [ - { - type: 'float', - name: 'scale', - default: 10, - }, -{ - type: 'float', - name: 'offset', - default: 0.1, +const baseAttrs = { + "aria-autocomplete": "list", + "aria-expanded": "false" +}; +function makeAttrs(id, selected) { + return { + "aria-autocomplete": "list", + "aria-expanded": "true", + "aria-activedescendant": id + "-" + selected, + "aria-controls": id + }; +} +const none = []; +function cmpOption(a, b) { + let dScore = b.match[0] - a.match[0]; + if (dScore) + return dScore; + return a.completion.label.localeCompare(b.completion.label); +} +function getUserEvent(tr) { + return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null; +} +class ActiveSource { + constructor(source, state, explicitPos = -1) { + this.source = source; + this.state = state; + this.explicitPos = explicitPos; } - ], - glsl: -` return vec4(vec3(_noise(vec3(_st*scale, offset*time))), 1.0);` -}, -{ - name: 'voronoi', - type: 'src', - inputs: [ - { - type: 'float', - name: 'scale', - default: 5, - }, -{ - type: 'float', - name: 'speed', - default: 0.3, - }, -{ - type: 'float', - name: 'blending', - default: 0.3, + hasResult() { return false; } + update(tr, conf) { + let event = getUserEvent(tr), value = this; + if (event) + value = value.handleUserEvent(tr, event, conf); + else if (tr.docChanged) + value = value.handleChange(tr); + else if (tr.selection && value.state != 0 /* Inactive */) + value = new ActiveSource(value.source, 0 /* Inactive */); + for (let effect of tr.effects) { + if (effect.is(startCompletionEffect)) + value = new ActiveSource(value.source, 1 /* Pending */, effect.value ? cur(tr.state) : -1); + else if (effect.is(closeCompletionEffect)) + value = new ActiveSource(value.source, 0 /* Inactive */); + else if (effect.is(setActiveEffect)) + for (let active of effect.value) + if (active.source == value.source) + value = active; + } + return value; } - ], - glsl: -` vec3 color = vec3(.0); - // Scale - _st *= scale; - // Tile the space - vec2 i_st = floor(_st); - vec2 f_st = fract(_st); - float m_dist = 10.; // minimun distance - vec2 m_point; // minimum point - for (int j=-1; j<=1; j++ ) { - for (int i=-1; i<=1; i++ ) { - vec2 neighbor = vec2(float(i),float(j)); - vec2 p = i_st + neighbor; - vec2 point = fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453); - point = 0.5 + 0.5*sin(time*speed + 6.2831*point); - vec2 diff = neighbor + point - f_st; - float dist = length(diff); - if( dist < m_dist ) { - m_dist = dist; - m_point = point; - } - } - } - // Assign a color using the closest point position - color += dot(m_point,vec2(.3,.6)); - color *= 1.0 - blending*m_dist; - return vec4(color, 1.0);` -}, -{ - name: 'osc', - type: 'src', - inputs: [ - { - type: 'float', - name: 'frequency', - default: 60, - }, -{ - type: 'float', - name: 'sync', - default: 0.1, - }, -{ - type: 'float', - name: 'offset', - default: 0, + handleUserEvent(tr, type, conf) { + return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* Pending */); } - ], - glsl: -` vec2 st = _st; - float r = sin((st.x-offset/frequency+time*sync)*frequency)*0.5 + 0.5; - float g = sin((st.x+time*sync)*frequency)*0.5 + 0.5; - float b = sin((st.x+offset/frequency+time*sync)*frequency)*0.5 + 0.5; - return vec4(r, g, b, 1.0);` -}, -{ - name: 'shape', - type: 'src', - inputs: [ - { - type: 'float', - name: 'sides', - default: 3, - }, -{ - type: 'float', - name: 'radius', - default: 0.3, - }, -{ - type: 'float', - name: 'smoothing', - default: 0.01, + handleChange(tr) { + return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes); } - ], - glsl: -` vec2 st = _st * 2. - 1.; - // Angle and radius from the current pixel - float a = atan(st.x,st.y)+3.1416; - float r = (2.*3.1416)/sides; - float d = cos(floor(.5+a/r)*r-a)*length(st); - return vec4(vec3(1.0-smoothstep(radius,radius + smoothing + 0.0000001,d)), 1.0);` -}, -{ - name: 'gradient', - type: 'src', - inputs: [ - { - type: 'float', - name: 'speed', - default: 0, + map(changes) { + return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos)); } - ], - glsl: -` return vec4(_st, sin(time*speed), 1.0);` -}, -{ - name: 'src', - type: 'src', - inputs: [ - { - type: 'sampler2D', - name: 'tex', - default: NaN, +} +class ActiveResult extends ActiveSource { + constructor(source, explicitPos, result, from, to, span) { + super(source, 2 /* Result */, explicitPos); + this.result = result; + this.from = from; + this.to = to; + this.span = span; } - ], - glsl: -` // vec2 uv = gl_FragCoord.xy/vec2(1280., 720.); - return texture2D(tex, fract(_st));` -}, -{ - name: 'solid', - type: 'src', - inputs: [ - { - type: 'float', - name: 'r', - default: 0, - }, -{ - type: 'float', - name: 'g', - default: 0, - }, -{ - type: 'float', - name: 'b', - default: 0, - }, -{ - type: 'float', - name: 'a', - default: 1, + hasResult() { return true; } + handleUserEvent(tr, type, conf) { + let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1); + let pos = cur(tr.state); + if ((this.explicitPos > -1 ? pos < from : pos <= from) || pos > to) + return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */); + let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos); + if (this.span && (from == to || this.span.test(tr.state.sliceDoc(from, to)))) + return new ActiveResult(this.source, explicitPos, this.result, from, to, this.span); + return new ActiveSource(this.source, 1 /* Pending */, explicitPos); } - ], - glsl: -` return vec4(r, g, b, a);` -}, -{ - name: 'rotate', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'angle', - default: 10, - }, -{ - type: 'float', - name: 'speed', - default: 0, + handleChange(tr) { + return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes); } - ], - glsl: -` vec2 xy = _st - vec2(0.5); - float ang = angle + speed *time; - xy = mat2(cos(ang),-sin(ang), sin(ang),cos(ang))*xy; - xy += 0.5; - return xy;` -}, -{ - name: 'scale', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'amount', - default: 1.5, + map(mapping) { + return mapping.empty ? this : + new ActiveResult(this.source, this.explicitPos < 0 ? -1 : mapping.mapPos(this.explicitPos), this.result, mapping.mapPos(this.from), mapping.mapPos(this.to, 1), this.span); + } +} +const startCompletionEffect = state.StateEffect.define(); +const closeCompletionEffect = state.StateEffect.define(); +const setActiveEffect = state.StateEffect.define({ + map(sources, mapping) { return sources.map(s => s.map(mapping)); } +}); +const setSelectedEffect = state.StateEffect.define(); +const completionState = state.StateField.define({ + create() { return CompletionState.start(); }, + update(value, tr) { return value.update(tr); }, + provide: f => [ + tooltip.showTooltip.from(f, val => val.tooltip), + view.EditorView.contentAttributes.from(f, state => state.attrs) + ] +}); + +const CompletionInteractMargin = 75; +/** +Returns a command that moves the completion selection forward or +backward by the given amount. +*/ +function moveCompletionSelection(forward, by = "option") { + return (view) => { + let cState = view.state.field(completionState, false); + if (!cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin) + return false; + let step = 1, tooltip$1; + if (by == "page" && (tooltip$1 = tooltip.getTooltip(view, cState.open.tooltip))) + step = Math.max(2, Math.floor(tooltip$1.dom.offsetHeight / + tooltip$1.dom.querySelector("li").offsetHeight) - 1); + let selected = cState.open.selected + step * (forward ? 1 : -1), { length } = cState.open.options; + if (selected < 0) + selected = by == "page" ? 0 : length - 1; + else if (selected >= length) + selected = by == "page" ? length - 1 : 0; + view.dispatch({ effects: setSelectedEffect.of(selected) }); + return true; + }; +} +/** +Accept the current completion. +*/ +const acceptCompletion = (view) => { + let cState = view.state.field(completionState, false); + if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin) + return false; + applyCompletion(view, cState.open.options[cState.open.selected]); + return true; +}; +/** +Explicitly start autocompletion. +*/ +const startCompletion = (view) => { + let cState = view.state.field(completionState, false); + if (!cState) + return false; + view.dispatch({ effects: startCompletionEffect.of(true) }); + return true; +}; +/** +Close the currently active completion. +*/ +const closeCompletion = (view) => { + let cState = view.state.field(completionState, false); + if (!cState || !cState.active.some(a => a.state != 0 /* Inactive */)) + return false; + view.dispatch({ effects: closeCompletionEffect.of(null) }); + return true; +}; +class RunningQuery { + constructor(active, context) { + this.active = active; + this.context = context; + this.time = Date.now(); + this.updates = []; + // Note that 'undefined' means 'not done yet', whereas 'null' means + // 'query returned null'. + this.done = undefined; + } +} +const DebounceTime = 50, MaxUpdateCount = 50, MinAbortTime = 1000; +const completionPlugin = view.ViewPlugin.fromClass(class { + constructor(view) { + this.view = view; + this.debounceUpdate = -1; + this.running = []; + this.debounceAccept = -1; + this.composing = 0 /* None */; + for (let active of view.state.field(completionState).active) + if (active.state == 1 /* Pending */) + this.startQuery(active); + } + update(update) { + let cState = update.state.field(completionState); + if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState) + return; + let doesReset = update.transactions.some(tr => { + return (tr.selection || tr.docChanged) && !getUserEvent(tr); + }); + for (let i = 0; i < this.running.length; i++) { + let query = this.running[i]; + if (doesReset || + query.updates.length + update.transactions.length > MaxUpdateCount && query.time - Date.now() > MinAbortTime) { + for (let handler of query.context.abortListeners) { + try { + handler(); + } + catch (e) { + view.logException(this.view.state, e); + } + } + query.context.abortListeners = null; + this.running.splice(i--, 1); + } + else { + query.updates.push(...update.transactions); + } + } + if (this.debounceUpdate > -1) + clearTimeout(this.debounceUpdate); + this.debounceUpdate = cState.active.some(a => a.state == 1 /* Pending */ && !this.running.some(q => q.active.source == a.source)) + ? setTimeout(() => this.startUpdate(), DebounceTime) : -1; + if (this.composing != 0 /* None */) + for (let tr of update.transactions) { + if (getUserEvent(tr) == "input") + this.composing = 2 /* Changed */; + else if (this.composing == 2 /* Changed */ && tr.selection) + this.composing = 3 /* ChangedAndMoved */; + } + } + startUpdate() { + this.debounceUpdate = -1; + let { state } = this.view, cState = state.field(completionState); + for (let active of cState.active) { + if (active.state == 1 /* Pending */ && !this.running.some(r => r.active.source == active.source)) + this.startQuery(active); + } + } + startQuery(active) { + let { state } = this.view, pos = cur(state); + let context = new CompletionContext(state, pos, active.explicitPos == pos); + let pending = new RunningQuery(active, context); + this.running.push(pending); + Promise.resolve(active.source(context)).then(result => { + if (!pending.context.aborted) { + pending.done = result || null; + this.scheduleAccept(); + } + }, err => { + this.view.dispatch({ effects: closeCompletionEffect.of(null) }); + view.logException(this.view.state, err); + }); + } + scheduleAccept() { + if (this.running.every(q => q.done !== undefined)) + this.accept(); + else if (this.debounceAccept < 0) + this.debounceAccept = setTimeout(() => this.accept(), DebounceTime); + } + // For each finished query in this.running, try to create a result + // or, if appropriate, restart the query. + accept() { + var _a; + if (this.debounceAccept > -1) + clearTimeout(this.debounceAccept); + this.debounceAccept = -1; + let updated = []; + let conf = this.view.state.facet(completionConfig); + for (let i = 0; i < this.running.length; i++) { + let query = this.running[i]; + if (query.done === undefined) + continue; + this.running.splice(i--, 1); + if (query.done) { + let active = new ActiveResult(query.active.source, query.active.explicitPos, query.done, query.done.from, (_a = query.done.to) !== null && _a !== void 0 ? _a : cur(query.updates.length ? query.updates[0].startState : this.view.state), query.done.span && query.done.filter !== false ? ensureAnchor(query.done.span, true) : null); + // Replay the transactions that happened since the start of + // the request and see if that preserves the result + for (let tr of query.updates) + active = active.update(tr, conf); + if (active.hasResult()) { + updated.push(active); + continue; + } + } + let current = this.view.state.field(completionState).active.find(a => a.source == query.active.source); + if (current && current.state == 1 /* Pending */) { + if (query.done == null) { + // Explicitly failed. Should clear the pending status if it + // hasn't been re-set in the meantime. + let active = new ActiveSource(query.active.source, 0 /* Inactive */); + for (let tr of query.updates) + active = active.update(tr, conf); + if (active.state != 1 /* Pending */) + updated.push(active); + } + else { + // Cleared by subsequent transactions. Restart. + this.startQuery(current); + } + } + } + if (updated.length) + this.view.dispatch({ effects: setActiveEffect.of(updated) }); + } +}, { + eventHandlers: { + compositionstart() { + this.composing = 1 /* Started */; + }, + compositionend() { + if (this.composing == 3 /* ChangedAndMoved */) { + // Safari fires compositionend events synchronously, possibly + // from inside an update, so dispatch asynchronously to avoid reentrancy + setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20); + } + this.composing = 0 /* None */; + } + } +}); + +const baseTheme = view.EditorView.baseTheme({ + ".cm-tooltip.cm-tooltip-autocomplete": { + "& > ul": { + fontFamily: "monospace", + whiteSpace: "nowrap", + overflow: "hidden auto", + maxWidth_fallback: "700px", + maxWidth: "min(700px, 95vw)", + minWidth: "250px", + maxHeight: "10em", + listStyle: "none", + margin: 0, + padding: 0, + "& > li": { + overflowX: "hidden", + textOverflow: "ellipsis", + cursor: "pointer", + padding: "1px 3px", + lineHeight: 1.2 + }, + } }, -{ - type: 'float', - name: 'xMult', - default: 1, + "&light .cm-tooltip-autocomplete ul li[aria-selected]": { + background: "#17c", + color: "white", }, -{ - type: 'float', - name: 'yMult', - default: 1, + "&dark .cm-tooltip-autocomplete ul li[aria-selected]": { + background: "#347", + color: "white", }, -{ - type: 'float', - name: 'offsetX', - default: 0.5, + ".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": { + content: '"···"', + opacity: 0.5, + display: "block", + textAlign: "center" }, -{ - type: 'float', - name: 'offsetY', - default: 0.5, - } - ], - glsl: -` vec2 xy = _st - vec2(offsetX, offsetY); - xy*=(1.0/vec2(amount*xMult, amount*yMult)); - xy+=vec2(offsetX, offsetY); - return xy; - ` -}, -{ - name: 'pixelate', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'pixelX', - default: 20, + ".cm-tooltip.cm-completionInfo": { + position: "absolute", + padding: "3px 9px", + width: "max-content", + maxWidth: "300px", }, -{ - type: 'float', - name: 'pixelY', - default: 20, - } - ], - glsl: -` vec2 xy = vec2(pixelX, pixelY); - return (floor(_st * xy) + 0.5)/xy;` -}, -{ - name: 'posterize', - type: 'color', - inputs: [ - { - type: 'float', - name: 'bins', - default: 3, + ".cm-completionInfo.cm-completionInfo-left": { right: "100%" }, + ".cm-completionInfo.cm-completionInfo-right": { left: "100%" }, + "&light .cm-snippetField": { backgroundColor: "#00000022" }, + "&dark .cm-snippetField": { backgroundColor: "#ffffff22" }, + ".cm-snippetFieldPosition": { + verticalAlign: "text-top", + width: 0, + height: "1.15em", + margin: "0 -0.7px -.7em", + borderLeft: "1.4px dotted #888" }, -{ - type: 'float', - name: 'gamma', - default: 0.6, - } - ], - glsl: -` vec4 c2 = pow(_c0, vec4(gamma)); - c2 *= vec4(bins); - c2 = floor(c2); - c2/= vec4(bins); - c2 = pow(c2, vec4(1.0/gamma)); - return vec4(c2.xyz, _c0.a);` -}, -{ - name: 'shift', - type: 'color', - inputs: [ - { - type: 'float', - name: 'r', - default: 0.5, + ".cm-completionMatchedText": { + textDecoration: "underline" }, -{ - type: 'float', - name: 'g', - default: 0, + ".cm-completionDetail": { + marginLeft: "0.5em", + fontStyle: "italic" }, -{ - type: 'float', - name: 'b', - default: 0, + ".cm-completionIcon": { + fontSize: "90%", + width: ".8em", + display: "inline-block", + textAlign: "center", + paddingRight: ".6em", + opacity: "0.6" }, -{ - type: 'float', - name: 'a', - default: 0, - } - ], - glsl: -` vec4 c2 = vec4(_c0); - c2.r = fract(c2.r + r); - c2.g = fract(c2.g + g); - c2.b = fract(c2.b + b); - c2.a = fract(c2.a + a); - return vec4(c2.rgba);` -}, -{ - name: 'repeat', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'repeatX', - default: 3, + ".cm-completionIcon-function, .cm-completionIcon-method": { + "&:after": { content: "'ƒ'" } }, -{ - type: 'float', - name: 'repeatY', - default: 3, + ".cm-completionIcon-class": { + "&:after": { content: "'○'" } }, -{ - type: 'float', - name: 'offsetX', - default: 0, + ".cm-completionIcon-interface": { + "&:after": { content: "'◌'" } }, -{ - type: 'float', - name: 'offsetY', - default: 0, - } - ], - glsl: -` vec2 st = _st * vec2(repeatX, repeatY); - st.x += step(1., mod(st.y,2.0)) * offsetX; - st.y += step(1., mod(st.x,2.0)) * offsetY; - return fract(st);` -}, -{ - name: 'modulateRepeat', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'repeatX', - default: 3, + ".cm-completionIcon-variable": { + "&:after": { content: "'𝑥'" } }, -{ - type: 'float', - name: 'repeatY', - default: 3, + ".cm-completionIcon-constant": { + "&:after": { content: "'𝐶'" } }, -{ - type: 'float', - name: 'offsetX', - default: 0.5, + ".cm-completionIcon-type": { + "&:after": { content: "'𝑡'" } }, -{ - type: 'float', - name: 'offsetY', - default: 0.5, - } - ], - glsl: -` vec2 st = _st * vec2(repeatX, repeatY); - st.x += step(1., mod(st.y,2.0)) + _c0.r * offsetX; - st.y += step(1., mod(st.x,2.0)) + _c0.g * offsetY; - return fract(st);` -}, -{ - name: 'repeatX', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'reps', - default: 3, + ".cm-completionIcon-enum": { + "&:after": { content: "'∪'" } }, -{ - type: 'float', - name: 'offset', - default: 0, - } - ], - glsl: -` vec2 st = _st * vec2(reps, 1.0); - // float f = mod(_st.y,2.0); - st.y += step(1., mod(st.x,2.0))* offset; - return fract(st);` -}, -{ - name: 'modulateRepeatX', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'reps', - default: 3, + ".cm-completionIcon-property": { + "&:after": { content: "'□'" } }, -{ - type: 'float', - name: 'offset', - default: 0.5, + ".cm-completionIcon-keyword": { + "&:after": { content: "'🔑\uFE0E'" } // Disable emoji rendering + }, + ".cm-completionIcon-namespace": { + "&:after": { content: "'▢'" } + }, + ".cm-completionIcon-text": { + "&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" } } - ], - glsl: -` vec2 st = _st * vec2(reps, 1.0); - // float f = mod(_st.y,2.0); - st.y += step(1., mod(st.x,2.0)) + _c0.r * offset; - return fract(st);` -}, -{ - name: 'repeatY', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'reps', - default: 3, - }, -{ - type: 'float', - name: 'offset', - default: 0, - } - ], - glsl: -` vec2 st = _st * vec2(1.0, reps); - // float f = mod(_st.y,2.0); - st.x += step(1., mod(st.y,2.0))* offset; - return fract(st);` -}, -{ - name: 'modulateRepeatY', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'reps', - default: 3, - }, -{ - type: 'float', - name: 'offset', - default: 0.5, - } - ], - glsl: -` vec2 st = _st * vec2(reps, 1.0); - // float f = mod(_st.y,2.0); - st.x += step(1., mod(st.y,2.0)) + _c0.r * offset; - return fract(st);` -}, -{ - name: 'kaleid', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'nSides', - default: 4, +}); + +class FieldPos { + constructor(field, line, from, to) { + this.field = field; + this.line = line; + this.from = from; + this.to = to; } - ], - glsl: -` vec2 st = _st; - st -= 0.5; - float r = length(st); - float a = atan(st.y, st.x); - float pi = 2.*3.1416; - a = mod(a,pi/nSides); - a = abs(a-pi/nSides/2.); - return r*vec2(cos(a), sin(a));` -}, -{ - name: 'modulateKaleid', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'nSides', - default: 4, +} +class FieldRange { + constructor(field, from, to) { + this.field = field; + this.from = from; + this.to = to; } - ], - glsl: -` vec2 st = _st - 0.5; - float r = length(st); - float a = atan(st.y, st.x); - float pi = 2.*3.1416; - a = mod(a,pi/nSides); - a = abs(a-pi/nSides/2.); - return (_c0.r+r)*vec2(cos(a), sin(a));` -}, -{ - name: 'scroll', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'scrollX', - default: 0.5, - }, -{ - type: 'float', - name: 'scrollY', - default: 0.5, - }, -{ - type: 'float', - name: 'speedX', - default: 0, - }, -{ - type: 'float', - name: 'speedY', - default: 0, + map(changes) { + return new FieldRange(this.field, changes.mapPos(this.from, -1), changes.mapPos(this.to, 1)); } - ], - glsl: -` - _st.x += scrollX + time*speedX; - _st.y += scrollY + time*speedY; - return fract(_st);` -}, -{ - name: 'scrollX', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'scrollX', - default: 0.5, - }, -{ - type: 'float', - name: 'speed', - default: 0, +} +class Snippet { + constructor(lines, fieldPositions) { + this.lines = lines; + this.fieldPositions = fieldPositions; } - ], - glsl: -` _st.x += scrollX + time*speed; - return fract(_st);` -}, -{ - name: 'modulateScrollX', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'scrollX', - default: 0.5, - }, -{ - type: 'float', - name: 'speed', - default: 0, + instantiate(state, pos) { + let text = [], lineStart = [pos]; + let lineObj = state.doc.lineAt(pos), baseIndent = /^\s*/.exec(lineObj.text)[0]; + for (let line of this.lines) { + if (text.length) { + let indent = baseIndent, tabs = /^\t*/.exec(line)[0].length; + for (let i = 0; i < tabs; i++) + indent += state.facet(language.indentUnit); + lineStart.push(pos + indent.length - tabs); + line = indent + line.slice(tabs); + } + text.push(line); + pos += line.length + 1; + } + let ranges = this.fieldPositions.map(pos => new FieldRange(pos.field, lineStart[pos.line] + pos.from, lineStart[pos.line] + pos.to)); + return { text, ranges }; } - ], - glsl: -` _st.x += _c0.r*scrollX + time*speed; - return fract(_st);` -}, -{ - name: 'scrollY', - type: 'coord', - inputs: [ - { - type: 'float', - name: 'scrollY', - default: 0.5, - }, -{ - type: 'float', - name: 'speed', - default: 0, + static parse(template) { + let fields = []; + let lines = [], positions = [], m; + for (let line of template.split(/\r\n?|\n/)) { + while (m = /[#$]\{(?:(\d+)(?::([^}]*))?|([^}]*))\}/.exec(line)) { + let seq = m[1] ? +m[1] : null, name = m[2] || m[3] || "", found = -1; + for (let i = 0; i < fields.length; i++) { + if (seq != null ? fields[i].seq == seq : name ? fields[i].name == name : false) + found = i; + } + if (found < 0) { + let i = 0; + while (i < fields.length && (seq == null || (fields[i].seq != null && fields[i].seq < seq))) + i++; + fields.splice(i, 0, { seq, name }); + found = i; + for (let pos of positions) + if (pos.field >= found) + pos.field++; + } + positions.push(new FieldPos(found, lines.length, m.index, m.index + name.length)); + line = line.slice(0, m.index) + name + line.slice(m.index + m[0].length); + } + lines.push(line); + } + return new Snippet(lines, positions); } - ], - glsl: -` _st.y += scrollY + time*speed; - return fract(_st);` -}, -{ - name: 'modulateScrollY', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'scrollY', - default: 0.5, - }, -{ - type: 'float', - name: 'speed', - default: 0, +} +let fieldMarker = view.Decoration.widget({ widget: new class extends view.WidgetType { + toDOM() { + let span = document.createElement("span"); + span.className = "cm-snippetFieldPosition"; + return span; + } + ignoreEvent() { return false; } + } }); +let fieldRange = view.Decoration.mark({ class: "cm-snippetField" }); +class ActiveSnippet { + constructor(ranges, active) { + this.ranges = ranges; + this.active = active; + this.deco = view.Decoration.set(ranges.map(r => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to))); } - ], - glsl: -` _st.y += _c0.r*scrollY + time*speed; - return fract(_st);` -}, -{ - name: 'add', - type: 'combine', - inputs: [ - { - type: 'float', - name: 'amount', - default: 1, + map(changes) { + return new ActiveSnippet(this.ranges.map(r => r.map(changes)), this.active); } - ], - glsl: -` return (_c0+_c1)*amount + _c0*(1.0-amount);` -}, -{ - name: 'sub', - type: 'combine', - inputs: [ - { - type: 'float', - name: 'amount', - default: 1, + selectionInsideField(sel) { + return sel.ranges.every(range => this.ranges.some(r => r.field == this.active && r.from <= range.from && r.to >= range.to)); } - ], - glsl: -` return (_c0-_c1)*amount + _c0*(1.0-amount);` -}, -{ - name: 'layer', - type: 'combine', - inputs: [ +} +const setActive = state.StateEffect.define({ + map(value, changes) { return value && value.map(changes); } +}); +const moveToField = state.StateEffect.define(); +const snippetState = state.StateField.define({ + create() { return null; }, + update(value, tr) { + for (let effect of tr.effects) { + if (effect.is(setActive)) + return effect.value; + if (effect.is(moveToField) && value) + return new ActiveSnippet(value.ranges, effect.value); + } + if (value && tr.docChanged) + value = value.map(tr.changes); + if (value && tr.selection && !value.selectionInsideField(tr.selection)) + value = null; + return value; + }, + provide: f => view.EditorView.decorations.from(f, val => val ? val.deco : view.Decoration.none) +}); +function fieldSelection(ranges, field) { + return state.EditorSelection.create(ranges.filter(r => r.field == field).map(r => state.EditorSelection.range(r.from, r.to))); +} +/** +Convert a snippet template to a function that can apply it. +Snippets are written using syntax like this: - ], - glsl: -` return vec4(mix(_c0.rgb, _c1.rgb, _c1.a), clamp(_c0.a + _c1.a, 0.0, 1.0));` -}, -{ - name: 'blend', - type: 'combine', - inputs: [ - { - type: 'float', - name: 'amount', - default: 0.5, - } - ], - glsl: -` return _c0*(1.0-amount)+_c1*amount;` -}, -{ - name: 'mult', - type: 'combine', - inputs: [ - { - type: 'float', - name: 'amount', - default: 1, - } - ], - glsl: -` return _c0*(1.0-amount)+(_c0*_c1)*amount;` -}, -{ - name: 'diff', - type: 'combine', - inputs: [ + "for (let ${index} = 0; ${index} < ${end}; ${index}++) {\n\t${}\n}" - ], - glsl: -` return vec4(abs(_c0.rgb-_c1.rgb), max(_c0.a, _c1.a));` -}, -{ - name: 'modulate', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'amount', - default: 0.1, +Each `${}` placeholder (you may also use `#{}`) indicates a field +that the user can fill in. Its name, if any, will be the default +content for the field. + +When the snippet is activated by calling the returned function, +the code is inserted at the given position. Newlines in the +template are indented by the indentation of the start line, plus +one [indent unit](https://codemirror.net/6/docs/ref/#language.indentUnit) per tab character after +the newline. + +On activation, (all instances of) the first field are selected. +The user can move between fields with Tab and Shift-Tab as long as +the fields are active. Moving to the last field or moving the +cursor out of the current field deactivates the fields. + +The order of fields defaults to textual order, but you can add +numbers to placeholders (`${1}` or `${1:defaultText}`) to provide +a custom order. +*/ +function snippet(template) { + let snippet = Snippet.parse(template); + return (editor, _completion, from, to) => { + let { text, ranges } = snippet.instantiate(editor.state, from); + let spec = { changes: { from, to, insert: state.Text.of(text) } }; + if (ranges.length) + spec.selection = fieldSelection(ranges, 0); + if (ranges.length > 1) { + let active = new ActiveSnippet(ranges, 0); + let effects = spec.effects = [setActive.of(active)]; + if (editor.state.field(snippetState, false) === undefined) + effects.push(state.StateEffect.appendConfig.of([snippetState, addSnippetKeymap, snippetPointerHandler, baseTheme])); + } + editor.dispatch(editor.state.update(spec)); + }; +} +function moveField(dir) { + return ({ state, dispatch }) => { + let active = state.field(snippetState, false); + if (!active || dir < 0 && active.active == 0) + return false; + let next = active.active + dir, last = dir > 0 && !active.ranges.some(r => r.field == next + dir); + dispatch(state.update({ + selection: fieldSelection(active.ranges, next), + effects: setActive.of(last ? null : new ActiveSnippet(active.ranges, next)) + })); + return true; + }; +} +/** +A command that clears the active snippet, if any. +*/ +const clearSnippet = ({ state, dispatch }) => { + let active = state.field(snippetState, false); + if (!active) + return false; + dispatch(state.update({ effects: setActive.of(null) })); + return true; +}; +/** +Move to the next snippet field, if available. +*/ +const nextSnippetField = moveField(1); +/** +Move to the previous snippet field, if available. +*/ +const prevSnippetField = moveField(-1); +const defaultSnippetKeymap = [ + { key: "Tab", run: nextSnippetField, shift: prevSnippetField }, + { key: "Escape", run: clearSnippet } +]; +/** +A facet that can be used to configure the key bindings used by +snippets. The default binds Tab to +[`nextSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.nextSnippetField), Shift-Tab to +[`prevSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.prevSnippetField), and Escape +to [`clearSnippet`](https://codemirror.net/6/docs/ref/#autocomplete.clearSnippet). +*/ +const snippetKeymap = state.Facet.define({ + combine(maps) { return maps.length ? maps[0] : defaultSnippetKeymap; } +}); +const addSnippetKeymap = state.Prec.highest(view.keymap.compute([snippetKeymap], state => state.facet(snippetKeymap))); +/** +Create a completion from a snippet. Returns an object with the +properties from `completion`, plus an `apply` function that +applies the snippet. +*/ +function snippetCompletion(template, completion) { + return Object.assign(Object.assign({}, completion), { apply: snippet(template) }); +} +const snippetPointerHandler = view.EditorView.domEventHandlers({ + mousedown(event, view) { + let active = view.state.field(snippetState, false), pos; + if (!active || (pos = view.posAtCoords({ x: event.clientX, y: event.clientY })) == null) + return false; + let match = active.ranges.find(r => r.from <= pos && r.to >= pos); + if (!match || match.field == active.active) + return false; + view.dispatch({ + selection: fieldSelection(active.ranges, match.field), + effects: setActive.of(active.ranges.some(r => r.field > match.field) ? new ActiveSnippet(active.ranges, match.field) : null) + }); + return true; } - ], - glsl: -` // return fract(st+(_c0.xy-0.5)*amount); - return _st + _c0.xy*amount;` -}, -{ - name: 'modulateScale', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'multiple', - default: 1, - }, -{ - type: 'float', - name: 'offset', - default: 1, +}); + +function wordRE(wordChars) { + let escaped = wordChars.replace(/[\\[.+*?(){|^$]/g, "\\$&"); + try { + return new RegExp(`[\\p{Alphabetic}\\p{Number}_${escaped}]+`, "ug"); } - ], - glsl: -` vec2 xy = _st - vec2(0.5); - xy*=(1.0/vec2(offset + multiple*_c0.r, offset + multiple*_c0.g)); - xy+=vec2(0.5); - return xy;` -}, -{ - name: 'modulatePixelate', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'multiple', - default: 10, - }, -{ - type: 'float', - name: 'offset', - default: 3, + catch (_a) { + return new RegExp(`[\w${escaped}]`, "g"); } - ], - glsl: -` vec2 xy = vec2(offset + _c0.x*multiple, offset + _c0.y*multiple); - return (floor(_st * xy) + 0.5)/xy;` -}, -{ - name: 'modulateRotate', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'multiple', - default: 1, - }, -{ - type: 'float', - name: 'offset', - default: 0, - } - ], - glsl: -` vec2 xy = _st - vec2(0.5); - float angle = offset + _c0.x * multiple; - xy = mat2(cos(angle),-sin(angle), sin(angle),cos(angle))*xy; - xy += 0.5; - return xy;` -}, -{ - name: 'modulateHue', - type: 'combineCoord', - inputs: [ - { - type: 'float', - name: 'amount', - default: 1, - } - ], - glsl: -` return _st + (vec2(_c0.g - _c0.r, _c0.b - _c0.g) * amount * 1.0/resolution);` -}, -{ - name: 'invert', - type: 'color', - inputs: [ - { - type: 'float', - name: 'amount', - default: 1, - } - ], - glsl: -` return vec4((1.0-_c0.rgb)*amount + _c0.rgb*(1.0-amount), _c0.a);` -}, -{ - name: 'contrast', - type: 'color', - inputs: [ - { - type: 'float', - name: 'amount', - default: 1.6, - } - ], - glsl: -` vec4 c = (_c0-vec4(0.5))*vec4(amount) + vec4(0.5); - return vec4(c.rgb, _c0.a);` -}, -{ - name: 'brightness', - type: 'color', - inputs: [ - { - type: 'float', - name: 'amount', - default: 0.4, - } - ], - glsl: -` return vec4(_c0.rgb + vec3(amount), _c0.a);` -}, -{ - name: 'mask', - type: 'combine', - inputs: [ - - ], - glsl: - ` float a = _luminance(_c1.rgb); - return vec4(_c0.rgb*a, a*_c0.a);` -}, - -{ - name: 'luma', - type: 'color', - inputs: [ - { - type: 'float', - name: 'threshold', - default: 0.5, - }, -{ - type: 'float', - name: 'tolerance', - default: 0.1, - } - ], - glsl: -` float a = smoothstep(threshold-(tolerance+0.0000001), threshold+(tolerance+0.0000001), _luminance(_c0.rgb)); - return vec4(_c0.rgb*a, a);` -}, -{ - name: 'thresh', - type: 'color', - inputs: [ - { - type: 'float', - name: 'threshold', - default: 0.5, - }, -{ - type: 'float', - name: 'tolerance', - default: 0.04, - } - ], - glsl: -` return vec4(vec3(smoothstep(threshold-(tolerance+0.0000001), threshold+(tolerance+0.0000001), _luminance(_c0.rgb))), _c0.a);` -}, -{ - name: 'color', - type: 'color', - inputs: [ - { - type: 'float', - name: 'r', - default: 1, - }, -{ - type: 'float', - name: 'g', - default: 1, - }, -{ - type: 'float', - name: 'b', - default: 1, - }, -{ - type: 'float', - name: 'a', - default: 1, - } - ], - glsl: -` vec4 c = vec4(r, g, b, a); - vec4 pos = step(0.0, c); // detect whether negative - // if > 0, return r * _c0 - // if < 0 return (1.0-r) * _c0 - return vec4(mix((1.0-_c0)*abs(c), c*_c0, pos));` -}, -{ - name: 'saturate', - type: 'color', - inputs: [ - { - type: 'float', - name: 'amount', - default: 2, - } - ], - glsl: -` const vec3 W = vec3(0.2125, 0.7154, 0.0721); - vec3 intensity = vec3(dot(_c0.rgb, W)); - return vec4(mix(intensity, _c0.rgb, amount), _c0.a);` -}, -{ - name: 'hue', - type: 'color', - inputs: [ - { - type: 'float', - name: 'hue', - default: 0.4, - } - ], - glsl: -` vec3 c = _rgbToHsv(_c0.rgb); - c.r += hue; - // c.r = fract(c.r); - return vec4(_hsvToRgb(c), _c0.a);` -}, -{ - name: 'colorama', - type: 'color', - inputs: [ - { - type: 'float', - name: 'amount', - default: 0.005, - } - ], - glsl: -` vec3 c = _rgbToHsv(_c0.rgb); - c += vec3(amount); - c = _hsvToRgb(c); - c = fract(c); - return vec4(c, _c0.a);` -}, -{ - name: 'prev', - type: 'src', - inputs: [ - - ], - glsl: -` return texture2D(prevBuffer, fract(_st));` -}, -{ - name: 'sum', - type: 'color', - inputs: [ - { - type: 'vec4', - name: 'scale', - default: 1, - } - ], - glsl: -` vec4 v = _c0 * s; - return v.r + v.g + v.b + v.a; - } - float sum(vec2 _st, vec4 s) { // vec4 is not a typo, because argument type is not overloaded - vec2 v = _st.xy * s.xy; - return v.x + v.y;` -}, -{ - name: 'r', - type: 'color', - inputs: [ - { - type: 'float', - name: 'scale', - default: 1, - }, -{ - type: 'float', - name: 'offset', - default: 0, - } - ], - glsl: -` return vec4(_c0.r * scale + offset);` -}, -{ - name: 'g', - type: 'color', - inputs: [ - { - type: 'float', - name: 'scale', - default: 1, - }, -{ - type: 'float', - name: 'offset', - default: 0, +} +function mapRE(re, f) { + return new RegExp(f(re.source), re.unicode ? "u" : ""); +} +const wordCaches = Object.create(null); +function wordCache(wordChars) { + return wordCaches[wordChars] || (wordCaches[wordChars] = new WeakMap); +} +function storeWords(doc, wordRE, result, seen, ignoreAt) { + for (let lines = doc.iterLines(), pos = 0; !lines.next().done;) { + let { value } = lines, m; + wordRE.lastIndex = 0; + while (m = wordRE.exec(value)) { + if (!seen[m[0]] && pos + m.index != ignoreAt) { + result.push({ type: "text", label: m[0] }); + seen[m[0]] = true; + if (result.length >= 2000 /* MaxList */) + return; + } + } + pos += value.length + 1; } - ], - glsl: -` return vec4(_c0.g * scale + offset);` -}, -{ - name: 'b', - type: 'color', - inputs: [ - { - type: 'float', - name: 'scale', - default: 1, - }, -{ - type: 'float', - name: 'offset', - default: 0, +} +function collectWords(doc, cache, wordRE, to, ignoreAt) { + let big = doc.length >= 1000 /* MinCacheLen */; + let cached = big && cache.get(doc); + if (cached) + return cached; + let result = [], seen = Object.create(null); + if (doc.children) { + let pos = 0; + for (let ch of doc.children) { + if (ch.length >= 1000 /* MinCacheLen */) { + for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) { + if (!seen[c.label]) { + seen[c.label] = true; + result.push(c); + } + } + } + else { + storeWords(ch, wordRE, result, seen, ignoreAt - pos); + } + pos += ch.length + 1; + } } - ], - glsl: -` return vec4(_c0.b * scale + offset);` -}, -{ - name: 'a', - type: 'color', - inputs: [ - { - type: 'float', - name: 'scale', - default: 1, - }, -{ - type: 'float', - name: 'offset', - default: 0, + else { + storeWords(doc, wordRE, result, seen, ignoreAt); } - ], - glsl: -` return vec4(_c0.a * scale + offset);` + if (big && result.length < 2000 /* MaxList */) + cache.set(doc, result); + return result; } -] - -},{}],16:[function(require,module,exports){ -// functions that are only used within other functions - -module.exports = { - _luminance: { - type: 'util', - glsl: `float _luminance(vec3 rgb){ - const vec3 W = vec3(0.2125, 0.7154, 0.0721); - return dot(rgb, W); - }` - }, - _noise: { - type: 'util', - glsl: ` - // Simplex 3D Noise - // by Ian McEwan, Ashima Arts - vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);} - vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} - - float _noise(vec3 v){ - const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; - const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); - - // First corner - vec3 i = floor(v + dot(v, C.yyy) ); - vec3 x0 = v - i + dot(i, C.xxx) ; - - // Other corners - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min( g.xyz, l.zxy ); - vec3 i2 = max( g.xyz, l.zxy ); - - // x0 = x0 - 0. + 0.0 * C - vec3 x1 = x0 - i1 + 1.0 * C.xxx; - vec3 x2 = x0 - i2 + 2.0 * C.xxx; - vec3 x3 = x0 - 1. + 3.0 * C.xxx; +/** +A completion source that will scan the document for words (using a +[character categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer)), and +return those as completions. +*/ +const completeAnyWord = context => { + let wordChars = context.state.languageDataAt("wordChars", context.pos).join(""); + let re = wordRE(wordChars); + let token = context.matchBefore(mapRE(re, s => s + "$")); + if (!token && !context.explicit) + return null; + let from = token ? token.from : context.pos; + let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* Range */, from); + return { from, options, span: mapRE(re, s => "^" + s) }; +}; - // Permutations - i = mod(i, 289.0 ); - vec4 p = permute( permute( permute( - i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) - + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); +/** +Returns an extension that enables autocompletion. +*/ +function autocompletion(config = {}) { + return [ + completionState, + completionConfig.of(config), + completionPlugin, + completionKeymapExt, + baseTheme + ]; +} +/** +Basic keybindings for autocompletion. - // Gradients - // ( N*N points uniformly over a square, mapped onto an octahedron.) - float n_ = 1.0/7.0; // N=7 - vec3 ns = n_ * D.wyz - D.xzx; + - Ctrl-Space: [`startCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.startCompletion) + - Escape: [`closeCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.closeCompletion) + - ArrowDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true)` + - ArrowUp: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(false)` + - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")` + - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")` + - Enter: [`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion) +*/ +const completionKeymap = [ + { key: "Ctrl-Space", run: startCompletion }, + { key: "Escape", run: closeCompletion }, + { key: "ArrowDown", run: moveCompletionSelection(true) }, + { key: "ArrowUp", run: moveCompletionSelection(false) }, + { key: "PageDown", run: moveCompletionSelection(true, "page") }, + { key: "PageUp", run: moveCompletionSelection(false, "page") }, + { key: "Enter", run: acceptCompletion } +]; +const completionKeymapExt = state.Prec.highest(view.keymap.computeN([completionConfig], state => state.facet(completionConfig).defaultKeymap ? [completionKeymap] : [])); +/** +Get the current completion status. When completions are available, +this will return `"active"`. When completions are pending (in the +process of being queried), this returns `"pending"`. Otherwise, it +returns `null`. +*/ +function completionStatus(state) { + let cState = state.field(completionState, false); + return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending" + : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null; +} +/** +Returns the available completions as an array. +*/ +function currentCompletions(state) { + var _a; + let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open; + return open ? open.options.map(o => o.completion) : []; +} +/** +Return the currently selected completion, if any. +*/ +function selectedCompletion(state) { + var _a; + let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open; + return open ? open.options[open.selected].completion : null; +} - vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) +exports.CompletionContext = CompletionContext; +exports.acceptCompletion = acceptCompletion; +exports.autocompletion = autocompletion; +exports.clearSnippet = clearSnippet; +exports.closeCompletion = closeCompletion; +exports.completeAnyWord = completeAnyWord; +exports.completeFromList = completeFromList; +exports.completionKeymap = completionKeymap; +exports.completionStatus = completionStatus; +exports.currentCompletions = currentCompletions; +exports.ifIn = ifIn; +exports.ifNotIn = ifNotIn; +exports.moveCompletionSelection = moveCompletionSelection; +exports.nextSnippetField = nextSnippetField; +exports.pickedCompletion = pickedCompletion; +exports.prevSnippetField = prevSnippetField; +exports.selectedCompletion = selectedCompletion; +exports.snippet = snippet; +exports.snippetCompletion = snippetCompletion; +exports.snippetKeymap = snippetKeymap; +exports.startCompletion = startCompletion; - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) +},{"@codemirror/language":27,"@codemirror/state":30,"@codemirror/text":31,"@codemirror/tooltip":32,"@codemirror/view":33}],24:[function(require,module,exports){ +'use strict'; - vec4 x = x_ *ns.x + ns.yyyy; - vec4 y = y_ *ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); +Object.defineProperty(exports, '__esModule', { value: true }); - vec4 b0 = vec4( x.xy, y.xy ); - vec4 b1 = vec4( x.zw, y.zw ); +var state = require('@codemirror/state'); +var text = require('@codemirror/text'); +var view = require('@codemirror/view'); +var matchbrackets = require('@codemirror/matchbrackets'); +var language = require('@codemirror/language'); +var common = require('@lezer/common'); - vec4 s0 = floor(b0)*2.0 + 1.0; - vec4 s1 = floor(b1)*2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); - - vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; - vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; - - vec3 p0 = vec3(a0.xy,h.x); - vec3 p1 = vec3(a0.zw,h.y); - vec3 p2 = vec3(a1.xy,h.z); - vec3 p3 = vec3(a1.zw,h.w); - - //Normalise gradients - vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - - // Mix final noise value - vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); - m = m * m; - return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), - dot(p2,x2), dot(p3,x3) ) ); - } - ` - }, - - - _rgbToHsv: { - type: 'util', - glsl: `vec3 _rgbToHsv(vec3 c){ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); - }` - }, - _hsvToRgb: { - type: 'util', - glsl: `vec3 _hsvToRgb(vec3 c){ - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); - }` - } -} - -},{}],17:[function(require,module,exports){ -const Webcam = require('./lib/webcam.js') -const Screen = require('./lib/screenmedia.js') - -class HydraSource { - constructor ({ regl, width, height, pb, label = ""}) { - this.label = label - this.regl = regl - this.src = null - this.dynamic = true - this.width = width - this.height = height - this.tex = this.regl.texture({ - // shape: [width, height] - shape: [ 1, 1 ] - }) - this.pb = pb - } - - init (opts, params) { - if ('src' in opts) { - this.src = opts.src - this.tex = this.regl.texture({ data: this.src, ...params }) - } - if ('dynamic' in opts) this.dynamic = opts.dynamic - } - - initCam (index, params) { - const self = this - Webcam(index) - .then(response => { - self.src = response.video - self.dynamic = true - self.tex = self.regl.texture({ data: self.src, ...params }) - }) - .catch(err => console.log('could not get camera', err)) - } - - initVideo (url = '', params) { - // const self = this - const vid = document.createElement('video') - vid.crossOrigin = 'anonymous' - vid.autoplay = true - vid.loop = true - vid.muted = true // mute in order to load without user interaction - const onload = vid.addEventListener('loadeddata', () => { - this.src = vid - vid.play() - this.tex = this.regl.texture({ data: this.src, ...params}) - this.dynamic = true - }) - vid.src = url - } - - initImage (url = '', params) { - const img = document.createElement('img') - img.crossOrigin = 'anonymous' - img.src = url - img.onload = () => { - this.src = img - this.dynamic = false - this.tex = this.regl.texture({ data: this.src, ...params}) - } - } - - initStream (streamName, params) { - // console.log("initing stream!", streamName) - let self = this - if (streamName && this.pb) { - this.pb.initSource(streamName) - - this.pb.on('got video', function (nick, video) { - if (nick === streamName) { - self.src = video - self.dynamic = true - self.tex = self.regl.texture({ data: self.src, ...params}) - } - }) - } - } - - // index only relevant in atom-hydra + desktop apps - initScreen (index = 0, params) { - const self = this - Screen() - .then(function (response) { - self.src = response.video - self.tex = self.regl.texture({ data: self.src, ...params}) - self.dynamic = true - // console.log("received screen input") - }) - .catch(err => console.log('could not get screen', err)) - } - - resize (width, height) { - this.width = width - this.height = height - } - - clear () { - if (this.src && this.src.srcObject) { - if (this.src.srcObject.getTracks) { - this.src.srcObject.getTracks().forEach(track => track.stop()) - } - } - this.src = null - this.tex = this.regl.texture({ shape: [ 1, 1 ] }) - } - - tick (time) { - // console.log(this.src, this.tex.width, this.tex.height) - if (this.src !== null && this.dynamic === true) { - if (this.src.videoWidth && this.src.videoWidth !== this.tex.width) { - console.log( - this.src.videoWidth, - this.src.videoHeight, - this.tex.width, - this.tex.height - ) - this.tex.resize(this.src.videoWidth, this.src.videoHeight) - } - - if (this.src.width && this.src.width !== this.tex.width) { - this.tex.resize(this.src.width, this.src.height) - } - - this.tex.subimage(this.src) - } - } - - getTexture () { - return this.tex - } -} - -module.exports = HydraSource - -},{"./lib/screenmedia.js":24,"./lib/webcam.js":26}],18:[function(require,module,exports){ -// WIP utils for working with arrays -// Possibly should be integrated with lfo extension, etc. -// to do: transform time rather than array values, similar to working with coordinates in hydra - -var easing = require('./easing-functions.js') - -var map = (num, in_min, in_max, out_min, out_max) => { - return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - -module.exports = { - init: () => { - - Array.prototype.fast = function(speed = 1) { - this._speed = speed - return this - } - - Array.prototype.smooth = function(smooth = 1) { - this._smooth = smooth - return this - } - - Array.prototype.ease = function(ease = 'linear') { - if (typeof ease == 'function') { - this._smooth = 1 - this._ease = ease - } - else if (easing[ease]){ - this._smooth = 1 - this._ease = easing[ease] - } - return this - } - - Array.prototype.offset = function(offset = 0.5) { - this._offset = offset%1.0 - return this - } - - // Array.prototype.bounce = function() { - // this.modifiers.bounce = true - // return this - // } - - Array.prototype.fit = function(low = 0, high =1) { - let lowest = Math.min(...this) - let highest = Math.max(...this) - var newArr = this.map((num) => map(num, lowest, highest, low, high)) - newArr._speed = this._speed - newArr._smooth = this._smooth - newArr._ease = this._ease - return newArr - } - }, - - getValue: (arr = []) => ({time, bpm}) =>{ - let speed = arr._speed ? arr._speed : 1 - let smooth = arr._smooth ? arr._smooth : 0 - let index = time * speed * (bpm / 60) + (arr._offset || 0) - - if (smooth!==0) { - let ease = arr._ease ? arr._ease : easing['linear'] - let _index = index - (smooth / 2) - let currValue = arr[Math.floor(_index % (arr.length))] - let nextValue = arr[Math.floor((_index + 1) % (arr.length))] - let t = Math.min((_index%1)/smooth,1) - return ease(t) * (nextValue - currValue) + currValue - } - else { - return arr[Math.floor(index % (arr.length))] - } - } -} - -},{"./easing-functions.js":20}],19:[function(require,module,exports){ -const Meyda = require('meyda') - -class Audio { - constructor ({ - numBins = 4, - cutoff = 2, - smooth = 0.4, - max = 15, - scale = 10, - isDrawing = false - }) { - this.vol = 0 - this.scale = scale - this.max = max - this.cutoff = cutoff - this.smooth = smooth - this.setBins(numBins) - - // beat detection from: https://github.com/therewasaguy/p5-music-viz/blob/gh-pages/demos/01d_beat_detect_amplitude/sketch.js - this.beat = { - holdFrames: 20, - threshold: 40, - _cutoff: 0, // adaptive based on sound state - decay: 0.98, - _framesSinceBeat: 0 // keeps track of frames - } - - this.onBeat = () => { - // console.log("beat") - } - - this.canvas = document.createElement('canvas') - this.canvas.width = 100 - this.canvas.height = 80 - this.canvas.style.width = "100px" - this.canvas.style.height = "80px" - this.canvas.style.position = 'absolute' - this.canvas.style.right = '0px' - this.canvas.style.bottom = '0px' - document.body.appendChild(this.canvas) - - this.isDrawing = isDrawing - this.ctx = this.canvas.getContext('2d') - this.ctx.fillStyle="#DFFFFF" - this.ctx.strokeStyle="#0ff" - this.ctx.lineWidth=0.5 - if(window.navigator.mediaDevices) { - window.navigator.mediaDevices.getUserMedia({video: false, audio: true}) - .then((stream) => { - // console.log('got mic stream', stream) - this.stream = stream - this.context = new AudioContext() - // this.context = new AudioContext() - let audio_stream = this.context.createMediaStreamSource(stream) - - // console.log(this.context) - this.meyda = Meyda.createMeydaAnalyzer({ - audioContext: this.context, - source: audio_stream, - featureExtractors: [ - 'loudness', - // 'perceptualSpread', - // 'perceptualSharpness', - // 'spectralCentroid' - ] - }) - }) - .catch((err) => console.log('ERROR', err)) - } - } - - detectBeat (level) { - //console.log(level, this.beat._cutoff) - if (level > this.beat._cutoff && level > this.beat.threshold) { - this.onBeat() - this.beat._cutoff = level *1.2 - this.beat._framesSinceBeat = 0 - } else { - if (this.beat._framesSinceBeat <= this.beat.holdFrames){ - this.beat._framesSinceBeat ++; - } else { - this.beat._cutoff *= this.beat.decay - this.beat._cutoff = Math.max( this.beat._cutoff, this.beat.threshold); - } - } - } - - tick() { - if(this.meyda){ - var features = this.meyda.get() - if(features && features !== null){ - this.vol = features.loudness.total - this.detectBeat(this.vol) - // reduce loudness array to number of bins - const reducer = (accumulator, currentValue) => accumulator + currentValue; - let spacing = Math.floor(features.loudness.specific.length/this.bins.length) - this.prevBins = this.bins.slice(0) - this.bins = this.bins.map((bin, index) => { - return features.loudness.specific.slice(index * spacing, (index + 1)*spacing).reduce(reducer) - }).map((bin, index) => { - // map to specified range - - // return (bin * (1.0 - this.smooth) + this.prevBins[index] * this.smooth) - return (bin * (1.0 - this.settings[index].smooth) + this.prevBins[index] * this.settings[index].smooth) - }) - // var y = this.canvas.height - scale*this.settings[index].cutoff - // this.ctx.beginPath() - // this.ctx.moveTo(index*spacing, y) - // this.ctx.lineTo((index+1)*spacing, y) - // this.ctx.stroke() - // - // var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) - this.fft = this.bins.map((bin, index) => ( - // Math.max(0, (bin - this.cutoff) / (this.max - this.cutoff)) - Math.max(0, (bin - this.settings[index].cutoff)/this.settings[index].scale) - )) - if(this.isDrawing) this.draw() - } - } - } - - setCutoff (cutoff) { - this.cutoff = cutoff - this.settings = this.settings.map((el) => { - el.cutoff = cutoff - return el - }) - } - - setSmooth (smooth) { - this.smooth = smooth - this.settings = this.settings.map((el) => { - el.smooth = smooth - return el - }) - } - - setBins (numBins) { - this.bins = Array(numBins).fill(0) - this.prevBins = Array(numBins).fill(0) - this.fft = Array(numBins).fill(0) - this.settings = Array(numBins).fill(0).map(() => ({ - cutoff: this.cutoff, - scale: this.scale, - smooth: this.smooth - })) - // to do: what to do in non-global mode? - this.bins.forEach((bin, index) => { - window['a' + index] = (scale = 1, offset = 0) => () => (a.fft[index] * scale + offset) - }) - // console.log(this.settings) - } - - setScale(scale){ - this.scale = scale - this.settings = this.settings.map((el) => { - el.scale = scale - return el - }) - } - - setMax(max) { - this.max = max - console.log('set max is deprecated') - } - hide() { - this.isDrawing = false - this.canvas.style.display = 'none' - } - - show() { - this.isDrawing = true - this.canvas.style.display = 'block' - - } - - draw () { - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) - var spacing = this.canvas.width / this.bins.length - var scale = this.canvas.height / (this.max * 2) - // console.log(this.bins) - this.bins.forEach((bin, index) => { - - var height = bin * scale - - this.ctx.fillRect(index * spacing, this.canvas.height - height, spacing, height) - - // console.log(this.settings[index]) - var y = this.canvas.height - scale*this.settings[index].cutoff - this.ctx.beginPath() - this.ctx.moveTo(index*spacing, y) - this.ctx.lineTo((index+1)*spacing, y) - this.ctx.stroke() - - var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) - this.ctx.beginPath() - this.ctx.moveTo(index*spacing, yMax) - this.ctx.lineTo((index+1)*spacing, yMax) - this.ctx.stroke() - }) - - - /*var y = this.canvas.height - scale*this.cutoff - this.ctx.beginPath() - this.ctx.moveTo(0, y) - this.ctx.lineTo(this.canvas.width, y) - this.ctx.stroke() - var yMax = this.canvas.height - scale*this.max - this.ctx.beginPath() - this.ctx.moveTo(0, yMax) - this.ctx.lineTo(this.canvas.width, yMax) - this.ctx.stroke()*/ - } -} - -module.exports = Audio - -},{"meyda":84}],20:[function(require,module,exports){ -// from https://gist.github.com/gre/1650294 - -module.exports = { - // no easing, no acceleration - linear: function (t) { return t }, - // accelerating from zero velocity - easeInQuad: function (t) { return t*t }, - // decelerating to zero velocity - easeOutQuad: function (t) { return t*(2-t) }, - // acceleration until halfway, then deceleration - easeInOutQuad: function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t }, - // accelerating from zero velocity - easeInCubic: function (t) { return t*t*t }, - // decelerating to zero velocity - easeOutCubic: function (t) { return (--t)*t*t+1 }, - // acceleration until halfway, then deceleration - easeInOutCubic: function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }, - // accelerating from zero velocity - easeInQuart: function (t) { return t*t*t*t }, - // decelerating to zero velocity - easeOutQuart: function (t) { return 1-(--t)*t*t*t }, - // acceleration until halfway, then deceleration - easeInOutQuart: function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t }, - // accelerating from zero velocity - easeInQuint: function (t) { return t*t*t*t*t }, - // decelerating to zero velocity - easeOutQuint: function (t) { return 1+(--t)*t*t*t*t }, - // acceleration until halfway, then deceleration - easeInOutQuint: function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t }, - // sin shape - sin: function (t) { return (1 + Math.sin(Math.PI*t-Math.PI/2))/2 } -} - -},{}],21:[function(require,module,exports){ -// https://github.com/mikolalysenko/mouse-event - -'use strict' - -function mouseButtons(ev) { - if(typeof ev === 'object') { - if('buttons' in ev) { - return ev.buttons - } else if('which' in ev) { - var b = ev.which - if(b === 2) { - return 4 - } else if(b === 3) { - return 2 - } else if(b > 0) { - return 1<<(b-1) - } - } else if('button' in ev) { - var b = ev.button - if(b === 1) { - return 4 - } else if(b === 2) { - return 2 - } else if(b >= 0) { - return 1< { - var initialCode = `` - - var sandbox = createSandbox(initialCode) - - var addToContext = (name, object) => { - initialCode += ` - var ${name} = ${object} - ` - sandbox = createSandbox(initialCode) - } - - - return { - addToContext: addToContext, - eval: (code) => sandbox.eval(code) - } - - function createSandbox (initial) { - eval(initial) - // optional params - var localEval = function (code) { - eval(code) - } - - // API/data for end-user - return { - eval: localEval - } - } -} - -},{}],24:[function(require,module,exports){ - -module.exports = function (options) { - return new Promise(function(resolve, reject) { - // async function startCapture(displayMediaOptions) { - navigator.mediaDevices.getDisplayMedia(options).then((stream) => { - const video = document.createElement('video') - video.srcObject = stream - video.addEventListener('loadedmetadata', () => { - video.play() - resolve({video: video}) - }) - }).catch((err) => reject(err)) - }) -} - -},{}],25:[function(require,module,exports){ -class VideoRecorder { - constructor(stream) { - this.mediaSource = new MediaSource() - this.stream = stream - - // testing using a recording as input - this.output = document.createElement('video') - this.output.autoplay = true - this.output.loop = true - - let self = this - this.mediaSource.addEventListener('sourceopen', () => { - console.log('MediaSource opened'); - self.sourceBuffer = self.mediaSource.addSourceBuffer('video/webm; codecs="vp8"'); - console.log('Source buffer: ', sourceBuffer); - }) - } - - start() { - // let options = {mimeType: 'video/webm'}; - -// let options = {mimeType: 'video/webm;codecs=h264'}; - let options = {mimeType: 'video/webm;codecs=vp9'}; - - this.recordedBlobs = [] - try { - this.mediaRecorder = new MediaRecorder(this.stream, options) - } catch (e0) { - console.log('Unable to create MediaRecorder with options Object: ', e0) - try { - options = {mimeType: 'video/webm,codecs=vp9'} - this.mediaRecorder = new MediaRecorder(this.stream, options) - } catch (e1) { - console.log('Unable to create MediaRecorder with options Object: ', e1) - try { - options = 'video/vp8' // Chrome 47 - this.mediaRecorder = new MediaRecorder(this.stream, options) - } catch (e2) { - alert('MediaRecorder is not supported by this browser.\n\n' + - 'Try Firefox 29 or later, or Chrome 47 or later, ' + - 'with Enable experimental Web Platform features enabled from chrome://flags.') - console.error('Exception while creating MediaRecorder:', e2) - return - } - } - } - console.log('Created MediaRecorder', this.mediaRecorder, 'with options', options); - this.mediaRecorder.onstop = this._handleStop.bind(this) - this.mediaRecorder.ondataavailable = this._handleDataAvailable.bind(this) - this.mediaRecorder.start(100) // collect 100ms of data - console.log('MediaRecorder started', this.mediaRecorder) - } - - - stop(){ - this.mediaRecorder.stop() - } - - _handleStop() { - //const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'}) - // const blob = new Blob(this.recordedBlobs, {type: 'video/webm;codecs=h264'}) - const blob = new Blob(this.recordedBlobs, {type: this.mediaRecorder.mimeType}) - const url = window.URL.createObjectURL(blob) - this.output.src = url - - const a = document.createElement('a') - a.style.display = 'none' - a.href = url - let d = new Date() - a.download = `hydra-${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}-${d.getHours()}.${d.getMinutes()}.${d.getSeconds()}.webm` - document.body.appendChild(a) - a.click() - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 300); - } - - _handleDataAvailable(event) { - if (event.data && event.data.size > 0) { - this.recordedBlobs.push(event.data); - } - } -} - -module.exports = VideoRecorder - -},{}],26:[function(require,module,exports){ -//const enumerateDevices = require('enumerate-devices') - -module.exports = function (deviceId) { - return navigator.mediaDevices.enumerateDevices() - .then(devices => devices.filter(devices => devices.kind === 'videoinput')) - .then(cameras => { - let constraints = { audio: false, video: true} - if (cameras[deviceId]) { - constraints['video'] = { - deviceId: { exact: cameras[deviceId].deviceId } - } - } - // console.log(cameras) - return window.navigator.mediaDevices.getUserMedia(constraints) - }) - .then(stream => { - const video = document.createElement('video') - video.setAttribute('autoplay', '') - video.setAttribute('muted', '') - video.setAttribute('playsinline', '') - // video.src = window.URL.createObjectURL(stream) - video.srcObject = stream - return new Promise((resolve, reject) => { - video.addEventListener('loadedmetadata', () => { - video.play().then(() => resolve({video: video})) - }) - }) - }) - .catch(console.log.bind(console)) -} - -},{}],27:[function(require,module,exports){ -//const transforms = require('./glsl-transforms.js') - -var Output = function ({ regl, precision, label = "", width, height}) { - this.regl = regl - this.precision = precision - this.label = label - this.positionBuffer = this.regl.buffer([ - [-2, 0], - [0, -2], - [2, 2] - ]) - - this.draw = () => {} - this.init() - this.pingPongIndex = 0 - - // for each output, create two fbos for pingponging - this.fbos = (Array(2)).fill().map(() => this.regl.framebuffer({ - color: this.regl.texture({ - mag: 'nearest', - width: width, - height: height, - format: 'rgba' - }), - depthStencil: false - })) - - // array containing render passes -// this.passes = [] -} - -Output.prototype.resize = function(width, height) { - this.fbos.forEach((fbo) => { - fbo.resize(width, height) - }) -// console.log(this) -} - - -Output.prototype.getCurrent = function () { - return this.fbos[this.pingPongIndex] -} - -Output.prototype.getTexture = function () { - var index = this.pingPongIndex ? 0 : 1 - return this.fbos[index] -} - -Output.prototype.init = function () { -// console.log('clearing') - this.transformIndex = 0 - this.fragHeader = ` - precision ${this.precision} float; - - uniform float time; - varying vec2 uv; - ` - - this.fragBody = `` - - this.vert = ` - precision ${this.precision} float; - attribute vec2 position; - varying vec2 uv; - - void main () { - uv = position; - gl_Position = vec4(2.0 * position - 1.0, 0, 1); - }` - - this.attributes = { - position: this.positionBuffer - } - this.uniforms = { - time: this.regl.prop('time'), - resolution: this.regl.prop('resolution') - } - - this.frag = ` - ${this.fragHeader} - - void main () { - vec4 c = vec4(0, 0, 0, 0); - vec2 st = uv; - ${this.fragBody} - gl_FragColor = c; - } - ` - return this -} - - -Output.prototype.render = function (passes) { - let pass = passes[0] - //console.log('pass', pass, this.pingPongIndex) - var self = this - var uniforms = Object.assign(pass.uniforms, { prevBuffer: () => { - //var index = this.pingPongIndex ? 0 : 1 - // var index = self.pingPong[(passIndex+1)%2] - // console.log('ping pong', self.pingPongIndex) - return self.fbos[self.pingPongIndex] - } - }) - - self.draw = self.regl({ - frag: pass.frag, - vert: self.vert, - attributes: self.attributes, - uniforms: uniforms, - count: 3, - framebuffer: () => { - self.pingPongIndex = self.pingPongIndex ? 0 : 1 - return self.fbos[self.pingPongIndex] - } - }) -} - - -Output.prototype.tick = function (props) { -// console.log(props) - this.draw(props) -} - -module.exports = Output - -},{}],28:[function(require,module,exports){ -module.exports = [ - { - key: 'src', - // color: '#f33' - }, - { - key: 'coord', - // color: '#ff3' - }, - { - key: 'color', - // color: '#3f3' - }, - { - key: 'combine', - // color: '#3ff' - }, - { - key: 'combineCoord', - // color: '#33f' - }, - { - key: 'ext', - }, - { - key: 'settings', - }, - { - key: 'array', - }, - { - key: 'audio', - }, -] - -},{}],29:[function(require,module,exports){ -function _arrayLikeToArray(arr, len) { - if (len == null || len > arr.length) len = arr.length; - - for (var i = 0, arr2 = new Array(len); i < len; i++) { - arr2[i] = arr[i]; - } - - return arr2; -} - -module.exports = _arrayLikeToArray, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],30:[function(require,module,exports){ -function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; -} - -module.exports = _arrayWithHoles, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],31:[function(require,module,exports){ -function _assertThisInitialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return self; -} - -module.exports = _assertThisInitialized, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],32:[function(require,module,exports){ -function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} - -module.exports = _classCallCheck, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],33:[function(require,module,exports){ -function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } -} - -function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - Object.defineProperty(Constructor, "prototype", { - writable: false - }); - return Constructor; -} - -module.exports = _createClass, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],34:[function(require,module,exports){ -function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; -} - -module.exports = _defineProperty, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],35:[function(require,module,exports){ -function _getPrototypeOf(o) { - module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { - return o.__proto__ || Object.getPrototypeOf(o); - }, module.exports.__esModule = true, module.exports["default"] = module.exports; - return _getPrototypeOf(o); -} - -module.exports = _getPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],36:[function(require,module,exports){ -var setPrototypeOf = require("./setPrototypeOf.js"); - -function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - writable: true, - configurable: true - } - }); - Object.defineProperty(subClass, "prototype", { - writable: false - }); - if (superClass) setPrototypeOf(subClass, superClass); -} - -module.exports = _inherits, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{"./setPrototypeOf.js":40}],37:[function(require,module,exports){ -function _iterableToArray(iter) { - if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); -} - -module.exports = _iterableToArray, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],38:[function(require,module,exports){ -function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); -} - -module.exports = _nonIterableRest, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],39:[function(require,module,exports){ -var _typeof = require("./typeof.js")["default"]; - -var assertThisInitialized = require("./assertThisInitialized.js"); - -function _possibleConstructorReturn(self, call) { - if (call && (_typeof(call) === "object" || typeof call === "function")) { - return call; - } else if (call !== void 0) { - throw new TypeError("Derived constructors may only return object or undefined"); - } - - return assertThisInitialized(self); +function updateSel(sel, by) { + return state.EditorSelection.create(sel.ranges.map(by), sel.mainIndex); } - -module.exports = _possibleConstructorReturn, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{"./assertThisInitialized.js":31,"./typeof.js":42}],40:[function(require,module,exports){ -function _setPrototypeOf(o, p) { - module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { - o.__proto__ = p; - return o; - }, module.exports.__esModule = true, module.exports["default"] = module.exports; - return _setPrototypeOf(o, p); +function setSel(state, selection) { + return state.update({ selection, scrollIntoView: true, userEvent: "select" }); } - -module.exports = _setPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],41:[function(require,module,exports){ -var arrayWithHoles = require("./arrayWithHoles.js"); - -var iterableToArray = require("./iterableToArray.js"); - -var unsupportedIterableToArray = require("./unsupportedIterableToArray.js"); - -var nonIterableRest = require("./nonIterableRest.js"); - -function _toArray(arr) { - return arrayWithHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableRest(); +function moveSel({ state, dispatch }, how) { + let selection = updateSel(state.selection, how); + if (selection.eq(state.selection)) + return false; + dispatch(setSel(state, selection)); + return true; } - -module.exports = _toArray, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{"./arrayWithHoles.js":30,"./iterableToArray.js":37,"./nonIterableRest.js":38,"./unsupportedIterableToArray.js":43}],42:[function(require,module,exports){ -function _typeof(obj) { - "@babel/helpers - typeof"; - - return (module.exports = _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { - return typeof obj; - } : function (obj) { - return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj); +function rangeEnd(range, forward) { + return state.EditorSelection.cursor(forward ? range.to : range.from); } - -module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{}],43:[function(require,module,exports){ -var arrayLikeToArray = require("./arrayLikeToArray.js"); - -function _unsupportedIterableToArray(o, minLen) { - if (!o) return; - if (typeof o === "string") return arrayLikeToArray(o, minLen); - var n = Object.prototype.toString.call(o).slice(8, -1); - if (n === "Object" && o.constructor) n = o.constructor.name; - if (n === "Map" || n === "Set") return Array.from(o); - if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen); +function cursorByChar(view, forward) { + return moveSel(view, range => range.empty ? view.moveByChar(range, forward) : rangeEnd(range, forward)); } - -module.exports = _unsupportedIterableToArray, module.exports.__esModule = true, module.exports["default"] = module.exports; -},{"./arrayLikeToArray.js":29}],44:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var state = require('@codemirror/state'); -var view = require('@codemirror/view'); -var tooltip = require('@codemirror/tooltip'); -var language = require('@codemirror/language'); -var text = require('@codemirror/text'); - /** -An instance of this is passed to completion source functions. +Move the selection one character to the left (which is backward in +left-to-right text, forward in right-to-left text). */ -class CompletionContext { - /** - Create a new completion context. (Mostly useful for testing - completion sources—in the editor, the extension will create - these for you.) - */ - constructor( - /** - The editor state that the completion happens in. - */ - state, - /** - The position at which the completion is happening. - */ - pos, - /** - Indicates whether completion was activated explicitly, or - implicitly by typing. The usual way to respond to this is to - only return completions when either there is part of a - completable entity before the cursor, or `explicit` is true. - */ - explicit) { - this.state = state; - this.pos = pos; - this.explicit = explicit; - /** - @internal - */ - this.abortListeners = []; - } - /** - Get the extent, content, and (if there is a token) type of the - token before `this.pos`. - */ - tokenBefore(types) { - let token = language.syntaxTree(this.state).resolveInner(this.pos, -1); - while (token && types.indexOf(token.name) < 0) - token = token.parent; - return token ? { from: token.from, to: this.pos, - text: this.state.sliceDoc(token.from, this.pos), - type: token.type } : null; - } - /** - Get the match of the given expression directly before the - cursor. - */ - matchBefore(expr) { - let line = this.state.doc.lineAt(this.pos); - let start = Math.max(line.from, this.pos - 250); - let str = line.text.slice(start - line.from, this.pos - line.from); - let found = str.search(ensureAnchor(expr, false)); - return found < 0 ? null : { from: start + found, to: this.pos, text: str.slice(found) }; - } - /** - Yields true when the query has been aborted. Can be useful in - asynchronous queries to avoid doing work that will be ignored. - */ - get aborted() { return this.abortListeners == null; } - /** - Allows you to register abort handlers, which will be called when - the query is - [aborted](https://codemirror.net/6/docs/ref/#autocomplete.CompletionContext.aborted). - */ - addEventListener(type, listener) { - if (type == "abort" && this.abortListeners) - this.abortListeners.push(listener); - } -} -function toSet(chars) { - let flat = Object.keys(chars).join(""); - let words = /\w/.test(flat); - if (words) - flat = flat.replace(/\w/g, ""); - return `[${words ? "\\w" : ""}${flat.replace(/[^\w\s]/g, "\\$&")}]`; -} -function prefixMatch(options) { - let first = Object.create(null), rest = Object.create(null); - for (let { label } of options) { - first[label[0]] = true; - for (let i = 1; i < label.length; i++) - rest[label[i]] = true; - } - let source = toSet(first) + toSet(rest) + "*$"; - return [new RegExp("^" + source), new RegExp(source)]; -} +const cursorCharLeft = view$1 => cursorByChar(view$1, view$1.textDirection != view.Direction.LTR); /** -Given a a fixed array of options, return an autocompleter that -completes them. +Move the selection one character to the right. */ -function completeFromList(list) { - let options = list.map(o => typeof o == "string" ? { label: o } : o); - let [span, match] = options.every(o => /^\w+$/.test(o.label)) ? [/\w*$/, /\w+$/] : prefixMatch(options); - return (context) => { - let token = context.matchBefore(match); - return token || context.explicit ? { from: token ? token.from : context.pos, options, span } : null; - }; -} +const cursorCharRight = view$1 => cursorByChar(view$1, view$1.textDirection == view.Direction.LTR); /** -Wrap the given completion source so that it will only fire when the -cursor is in a syntax node with one of the given names. +Move the selection one character forward. */ -function ifIn(nodes, source) { - return (context) => { - for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) - if (nodes.indexOf(pos.name) > -1) - return source(context); - return null; - }; -} +const cursorCharForward = view => cursorByChar(view, true); /** -Wrap the given completion source so that it will not fire when the -cursor is in a syntax node with one of the given names. +Move the selection one character backward. */ -function ifNotIn(nodes, source) { - return (context) => { - for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) - if (nodes.indexOf(pos.name) > -1) - return null; - return source(context); - }; -} -class Option { - constructor(completion, source, match) { - this.completion = completion; - this.source = source; - this.match = match; - } -} -function cur(state) { return state.selection.main.head; } -// Make sure the given regexp has a $ at its end and, if `start` is -// true, a ^ at its start. -function ensureAnchor(expr, start) { - var _a; - let { source } = expr; - let addStart = start && source[0] != "^", addEnd = source[source.length - 1] != "$"; - if (!addStart && !addEnd) - return expr; - return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : (expr.ignoreCase ? "i" : "")); +const cursorCharBackward = view => cursorByChar(view, false); +function cursorByGroup(view, forward) { + return moveSel(view, range => range.empty ? view.moveByGroup(range, forward) : rangeEnd(range, forward)); } /** -This annotation is added to transactions that are produced by -picking a completion. +Move the selection to the left across one group of word or +non-word (but also non-space) characters. */ -const pickedCompletion = state.Annotation.define(); -function applyCompletion(view, option) { - let apply = option.completion.apply || option.completion.label; - let result = option.source; - if (typeof apply == "string") { - view.dispatch({ - changes: { from: result.from, to: result.to, insert: apply }, - selection: { anchor: result.from + apply.length }, - userEvent: "input.complete", - annotations: pickedCompletion.of(option.completion) - }); - } - else { - apply(view, option.completion, result.from, result.to); - } -} -const SourceCache = new WeakMap(); -function asSource(source) { - if (!Array.isArray(source)) - return source; - let known = SourceCache.get(source); - if (!known) - SourceCache.set(source, known = completeFromList(source)); - return known; -} - -// A pattern matcher for fuzzy completion matching. Create an instance -// once for a pattern, and then use that to match any number of -// completions. -class FuzzyMatcher { - constructor(pattern) { - this.pattern = pattern; - this.chars = []; - this.folded = []; - // Buffers reused by calls to `match` to track matched character - // positions. - this.any = []; - this.precise = []; - this.byWord = []; - for (let p = 0; p < pattern.length;) { - let char = text.codePointAt(pattern, p), size = text.codePointSize(char); - this.chars.push(char); - let part = pattern.slice(p, p + size), upper = part.toUpperCase(); - this.folded.push(text.codePointAt(upper == part ? part.toLowerCase() : upper, 0)); - p += size; - } - this.astral = pattern.length != this.chars.length; - } - // Matches a given word (completion) against the pattern (input). - // Will return null for no match, and otherwise an array that starts - // with the match score, followed by any number of `from, to` pairs - // indicating the matched parts of `word`. - // - // The score is a number that is more negative the worse the match - // is. See `Penalty` above. - match(word) { - if (this.pattern.length == 0) - return [0]; - if (word.length < this.pattern.length) - return null; - let { chars, folded, any, precise, byWord } = this; - // For single-character queries, only match when they occur right - // at the start - if (chars.length == 1) { - let first = text.codePointAt(word, 0); - return first == chars[0] ? [0, 0, text.codePointSize(first)] - : first == folded[0] ? [-200 /* CaseFold */, 0, text.codePointSize(first)] : null; - } - let direct = word.indexOf(this.pattern); - if (direct == 0) - return [0, 0, this.pattern.length]; - let len = chars.length, anyTo = 0; - if (direct < 0) { - for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) { - let next = text.codePointAt(word, i); - if (next == chars[anyTo] || next == folded[anyTo]) - any[anyTo++] = i; - i += text.codePointSize(next); - } - // No match, exit immediately - if (anyTo < len) - return null; - } - // This tracks the extent of the precise (non-folded, not - // necessarily adjacent) match - let preciseTo = 0; - // Tracks whether there is a match that hits only characters that - // appear to be starting words. `byWordFolded` is set to true when - // a case folded character is encountered in such a match - let byWordTo = 0, byWordFolded = false; - // If we've found a partial adjacent match, these track its state - let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1; - let hasLower = /[a-z]/.test(word), wordAdjacent = true; - // Go over the option's text, scanning for the various kinds of matches - for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* NonWord */; i < e && byWordTo < len;) { - let next = text.codePointAt(word, i); - if (direct < 0) { - if (preciseTo < len && next == chars[preciseTo]) - precise[preciseTo++] = i; - if (adjacentTo < len) { - if (next == chars[adjacentTo] || next == folded[adjacentTo]) { - if (adjacentTo == 0) - adjacentStart = i; - adjacentEnd = i + 1; - adjacentTo++; - } - else { - adjacentTo = 0; - } +const cursorGroupLeft = view$1 => cursorByGroup(view$1, view$1.textDirection != view.Direction.LTR); +/** +Move the selection one group to the right. +*/ +const cursorGroupRight = view$1 => cursorByGroup(view$1, view$1.textDirection == view.Direction.LTR); +/** +Move the selection one group forward. +*/ +const cursorGroupForward = view => cursorByGroup(view, true); +/** +Move the selection one group backward. +*/ +const cursorGroupBackward = view => cursorByGroup(view, false); +function moveBySubword(view, range, forward) { + let categorize = view.state.charCategorizer(range.from); + return view.moveByChar(range, forward, start => { + let cat = state.CharCategory.Space, pos = range.from; + let done = false, sawUpper = false, sawLower = false; + let step = (next) => { + if (done) + return false; + pos += forward ? next.length : -next.length; + let nextCat = categorize(next), ahead; + if (cat == state.CharCategory.Space) + cat = nextCat; + if (cat != nextCat) + return false; + if (cat == state.CharCategory.Word) { + if (next.toLowerCase() == next) { + if (!forward && sawUpper) + return false; + sawLower = true; + } + else if (sawLower) { + if (forward) + return false; + done = true; + } + else { + if (sawUpper && forward && categorize(ahead = view.state.sliceDoc(pos, pos + 1)) == state.CharCategory.Word && + ahead.toLowerCase() == ahead) + return false; + sawUpper = true; } } - let ch, type = next < 0xff - ? (next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 /* Lower */ : next >= 65 && next <= 90 ? 1 /* Upper */ : 0 /* NonWord */) - : ((ch = text.fromCodePoint(next)) != ch.toLowerCase() ? 1 /* Upper */ : ch != ch.toUpperCase() ? 2 /* Lower */ : 0 /* NonWord */); - if (!i || type == 1 /* Upper */ && hasLower || prevType == 0 /* NonWord */ && type != 0 /* NonWord */) { - if (chars[byWordTo] == next || (folded[byWordTo] == next && (byWordFolded = true))) - byWord[byWordTo++] = i; - else if (byWord.length) - wordAdjacent = false; - } - prevType = type; - i += text.codePointSize(next); - } - if (byWordTo == len && byWord[0] == 0 && wordAdjacent) - return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0), byWord, word); - if (adjacentTo == len && adjacentStart == 0) - return [-200 /* CaseFold */ - word.length, 0, adjacentEnd]; - if (direct > -1) - return [-700 /* NotStart */ - word.length, direct, direct + this.pattern.length]; - if (adjacentTo == len) - return [-200 /* CaseFold */ + -700 /* NotStart */ - word.length, adjacentStart, adjacentEnd]; - if (byWordTo == len) - return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0) + -700 /* NotStart */ + - (wordAdjacent ? 0 : -1100 /* Gap */), byWord, word); - return chars.length == 2 ? null : this.result((any[0] ? -700 /* NotStart */ : 0) + -200 /* CaseFold */ + -1100 /* Gap */, any, word); - } - result(score, positions, word) { - let result = [score - word.length], i = 1; - for (let pos of positions) { - let to = pos + (this.astral ? text.codePointSize(text.codePointAt(word, pos)) : 1); - if (i > 1 && result[i - 1] == pos) - result[i - 1] = to; - else { - result[i++] = pos; - result[i++] = to; - } - } - return result; - } + return true; + }; + step(start); + return step; + }); } - -const completionConfig = state.Facet.define({ - combine(configs) { - return state.combineConfig(configs, { - activateOnTyping: true, - override: null, - maxRenderedOptions: 100, - defaultKeymap: true, - optionClass: () => "", - aboveCursor: false, - icons: true, - addToOptions: [] - }, { - defaultKeymap: (a, b) => a && b, - icons: (a, b) => a && b, - optionClass: (a, b) => c => joinClass(a(c), b(c)), - addToOptions: (a, b) => a.concat(b) - }); +function cursorBySubword(view, forward) { + return moveSel(view, range => range.empty ? moveBySubword(view, range, forward) : rangeEnd(range, forward)); +} +/** +Move the selection one group or camel-case subword forward. +*/ +const cursorSubwordForward = view => cursorBySubword(view, true); +/** +Move the selection one group or camel-case subword backward. +*/ +const cursorSubwordBackward = view => cursorBySubword(view, false); +function interestingNode(state, node, bracketProp) { + if (node.type.prop(bracketProp)) + return true; + let len = node.to - node.from; + return len && (len > 2 || /[^\s,.;:]/.test(state.sliceDoc(node.from, node.to))) || node.firstChild; +} +function moveBySyntax(state$1, start, forward) { + let pos = language.syntaxTree(state$1).resolveInner(start.head); + let bracketProp = forward ? common.NodeProp.closedBy : common.NodeProp.openedBy; + // Scan forward through child nodes to see if there's an interesting + // node ahead. + for (let at = start.head;;) { + let next = forward ? pos.childAfter(at) : pos.childBefore(at); + if (!next) + break; + if (interestingNode(state$1, next, bracketProp)) + pos = next; + else + at = forward ? next.to : next.from; } -}); -function joinClass(a, b) { - return a ? b ? a + " " + b : a : b; + let bracket = pos.type.prop(bracketProp), match, newPos; + if (bracket && (match = forward ? matchbrackets.matchBrackets(state$1, pos.from, 1) : matchbrackets.matchBrackets(state$1, pos.to, -1)) && match.matched) + newPos = forward ? match.end.to : match.end.from; + else + newPos = forward ? pos.to : pos.from; + return state.EditorSelection.cursor(newPos, forward ? -1 : 1); } - -function optionContent(config) { - let content = config.addToOptions.slice(); - if (config.icons) - content.push({ - render(completion) { - let icon = document.createElement("div"); - icon.classList.add("cm-completionIcon"); - if (completion.type) - icon.classList.add(...completion.type.split(/\s+/g).map(cls => "cm-completionIcon-" + cls)); - icon.setAttribute("aria-hidden", "true"); - return icon; - }, - position: 20 - }); - content.push({ - render(completion, _s, match) { - let labelElt = document.createElement("span"); - labelElt.className = "cm-completionLabel"; - let { label } = completion, off = 0; - for (let j = 1; j < match.length;) { - let from = match[j++], to = match[j++]; - if (from > off) - labelElt.appendChild(document.createTextNode(label.slice(off, from))); - let span = labelElt.appendChild(document.createElement("span")); - span.appendChild(document.createTextNode(label.slice(from, to))); - span.className = "cm-completionMatchedText"; - off = to; - } - if (off < label.length) - labelElt.appendChild(document.createTextNode(label.slice(off))); - return labelElt; - }, - position: 50 - }, { - render(completion) { - if (!completion.detail) - return null; - let detailElt = document.createElement("span"); - detailElt.className = "cm-completionDetail"; - detailElt.textContent = completion.detail; - return detailElt; - }, - position: 80 +/** +Move the cursor over the next syntactic element to the left. +*/ +const cursorSyntaxLeft = view$1 => moveSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection != view.Direction.LTR)); +/** +Move the cursor over the next syntactic element to the right. +*/ +const cursorSyntaxRight = view$1 => moveSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection == view.Direction.LTR)); +function cursorByLine(view, forward) { + return moveSel(view, range => { + if (!range.empty) + return rangeEnd(range, forward); + let moved = view.moveVertically(range, forward); + return moved.head != range.head ? moved : view.moveToLineBoundary(range, forward); }); - return content.sort((a, b) => a.position - b.position).map(a => a.render); } -function createInfoDialog(option, view$1) { - let dom = document.createElement("div"); - dom.className = "cm-tooltip cm-completionInfo"; - let { info } = option.completion; - if (typeof info == "string") { - dom.textContent = info; - } - else { - let content = info(option.completion); - if (content.then) - content.then(node => dom.appendChild(node), e => view.logException(view$1.state, e, "completion info")); - else - dom.appendChild(content); - } - return dom; +/** +Move the selection one line up. +*/ +const cursorLineUp = view => cursorByLine(view, false); +/** +Move the selection one line down. +*/ +const cursorLineDown = view => cursorByLine(view, true); +function cursorByPage(view$1, forward) { + let { state } = view$1, selection = updateSel(state.selection, range => { + return range.empty ? view$1.moveVertically(range, forward, view$1.dom.clientHeight) : rangeEnd(range, forward); + }); + if (selection.eq(state.selection)) + return false; + let startPos = view$1.coordsAtPos(state.selection.main.head); + let scrollRect = view$1.scrollDOM.getBoundingClientRect(); + view$1.dispatch(setSel(state, selection), { + effects: startPos && startPos.top > scrollRect.top && startPos.bottom < scrollRect.bottom + ? view.EditorView.scrollIntoView(selection.main.head, { y: "start", yMargin: startPos.top - scrollRect.top }) + : undefined + }); + return true; } -function rangeAroundSelected(total, selected, max) { - if (total <= max) - return { from: 0, to: total }; - if (selected <= (total >> 1)) { - let off = Math.floor(selected / max); - return { from: off * max, to: (off + 1) * max }; +/** +Move the selection one page up. +*/ +const cursorPageUp = view => cursorByPage(view, false); +/** +Move the selection one page down. +*/ +const cursorPageDown = view => cursorByPage(view, true); +function moveByLineBoundary(view, start, forward) { + let line = view.lineBlockAt(start.head), moved = view.moveToLineBoundary(start, forward); + if (moved.head == start.head && moved.head != (forward ? line.to : line.from)) + moved = view.moveToLineBoundary(start, forward, false); + if (!forward && moved.head == line.from && line.length) { + let space = /^\s*/.exec(view.state.sliceDoc(line.from, Math.min(line.from + 100, line.to)))[0].length; + if (space && start.head != line.from + space) + moved = state.EditorSelection.cursor(line.from + space); } - let off = Math.floor((total - selected) / max); - return { from: total - (off + 1) * max, to: total - off * max }; + return moved; } -class CompletionTooltip { - constructor(view, stateField) { - this.view = view; - this.stateField = stateField; - this.info = null; - this.placeInfo = { - read: () => this.measureInfo(), - write: (pos) => this.positionInfo(pos), - key: this - }; - let cState = view.state.field(stateField); - let { options, selected } = cState.open; - let config = view.state.facet(completionConfig); - this.optionContent = optionContent(config); - this.optionClass = config.optionClass; - this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions); - this.dom = document.createElement("div"); - this.dom.className = "cm-tooltip-autocomplete"; - this.dom.addEventListener("mousedown", (e) => { - for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) { - if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) { - applyCompletion(view, options[+match[1]]); - e.preventDefault(); - return; - } - } - }); - this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range)); - this.list.addEventListener("scroll", () => { - if (this.info) - this.view.requestMeasure(this.placeInfo); - }); - } - mount() { this.updateSel(); } - update(update) { - if (update.state.field(this.stateField) != update.startState.field(this.stateField)) - this.updateSel(); - } - positioned() { - if (this.info) - this.view.requestMeasure(this.placeInfo); - } - updateSel() { - let cState = this.view.state.field(this.stateField), open = cState.open; - if (open.selected < this.range.from || open.selected >= this.range.to) { - this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions); - this.list.remove(); - this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range)); - this.list.addEventListener("scroll", () => { - if (this.info) - this.view.requestMeasure(this.placeInfo); - }); - } - if (this.updateSelectedOption(open.selected)) { - if (this.info) { - this.info.remove(); - this.info = null; - } - let option = open.options[open.selected]; - if (option.completion.info) { - this.info = this.dom.appendChild(createInfoDialog(option, this.view)); - this.view.requestMeasure(this.placeInfo); - } - } - } - updateSelectedOption(selected) { - let set = null; - for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) { - if (i == selected) { - if (!opt.hasAttribute("aria-selected")) { - opt.setAttribute("aria-selected", "true"); - set = opt; - } - } - else { - if (opt.hasAttribute("aria-selected")) - opt.removeAttribute("aria-selected"); - } - } - if (set) - scrollIntoView(this.list, set); - return set; - } - measureInfo() { - let sel = this.dom.querySelector("[aria-selected]"); - if (!sel || !this.info) - return null; - let listRect = this.dom.getBoundingClientRect(); - let infoRect = this.info.getBoundingClientRect(); - let selRect = sel.getBoundingClientRect(); - if (selRect.top > Math.min(innerHeight, listRect.bottom) - 10 || selRect.bottom < Math.max(0, listRect.top) + 10) - return null; - let top = Math.max(0, Math.min(selRect.top, innerHeight - infoRect.height)) - listRect.top; - let left = this.view.textDirection == view.Direction.RTL; - let spaceLeft = listRect.left, spaceRight = innerWidth - listRect.right; - if (left && spaceLeft < Math.min(infoRect.width, spaceRight)) - left = false; - else if (!left && spaceRight < Math.min(infoRect.width, spaceLeft)) - left = true; - return { top, left }; - } - positionInfo(pos) { - if (this.info) { - this.info.style.top = (pos ? pos.top : -1e6) + "px"; - if (pos) { - this.info.classList.toggle("cm-completionInfo-left", pos.left); - this.info.classList.toggle("cm-completionInfo-right", !pos.left); - } - } - } - createListBox(options, id, range) { - const ul = document.createElement("ul"); - ul.id = id; - ul.setAttribute("role", "listbox"); - for (let i = range.from; i < range.to; i++) { - let { completion, match } = options[i]; - const li = ul.appendChild(document.createElement("li")); - li.id = id + "-" + i; - li.setAttribute("role", "option"); - let cls = this.optionClass(completion); - if (cls) - li.className = cls; - for (let source of this.optionContent) { - let node = source(completion, this.view.state, match); - if (node) - li.appendChild(node); - } - } - if (range.from) - ul.classList.add("cm-completionListIncompleteTop"); - if (range.to < options.length) - ul.classList.add("cm-completionListIncompleteBottom"); - return ul; - } +/** +Move the selection to the next line wrap point, or to the end of +the line if there isn't one left on this line. +*/ +const cursorLineBoundaryForward = view => moveSel(view, range => moveByLineBoundary(view, range, true)); +/** +Move the selection to previous line wrap point, or failing that to +the start of the line. If the line is indented, and the cursor +isn't already at the end of the indentation, this will move to the +end of the indentation instead of the start of the line. +*/ +const cursorLineBoundaryBackward = view => moveSel(view, range => moveByLineBoundary(view, range, false)); +/** +Move the selection to the start of the line. +*/ +const cursorLineStart = view => moveSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).from, 1)); +/** +Move the selection to the end of the line. +*/ +const cursorLineEnd = view => moveSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).to, -1)); +function toMatchingBracket(state$1, dispatch, extend) { + let found = false, selection = updateSel(state$1.selection, range => { + let matching = matchbrackets.matchBrackets(state$1, range.head, -1) + || matchbrackets.matchBrackets(state$1, range.head, 1) + || (range.head > 0 && matchbrackets.matchBrackets(state$1, range.head - 1, 1)) + || (range.head < state$1.doc.length && matchbrackets.matchBrackets(state$1, range.head + 1, -1)); + if (!matching || !matching.end) + return range; + found = true; + let head = matching.start.from == range.head ? matching.end.to : matching.end.from; + return extend ? state.EditorSelection.range(range.anchor, head) : state.EditorSelection.cursor(head); + }); + if (!found) + return false; + dispatch(setSel(state$1, selection)); + return true; } -// We allocate a new function instance every time the completion -// changes to force redrawing/repositioning of the tooltip -function completionTooltip(stateField) { - return (view) => new CompletionTooltip(view, stateField); +/** +Move the selection to the bracket matching the one it is currently +on, if any. +*/ +const cursorMatchingBracket = ({ state, dispatch }) => toMatchingBracket(state, dispatch, false); +/** +Extend the selection to the bracket matching the one the selection +head is currently on, if any. +*/ +const selectMatchingBracket = ({ state, dispatch }) => toMatchingBracket(state, dispatch, true); +function extendSel(view, how) { + let selection = updateSel(view.state.selection, range => { + let head = how(range); + return state.EditorSelection.range(range.anchor, head.head, head.goalColumn); + }); + if (selection.eq(view.state.selection)) + return false; + view.dispatch(setSel(view.state, selection)); + return true; } -function scrollIntoView(container, element) { - let parent = container.getBoundingClientRect(); - let self = element.getBoundingClientRect(); - if (self.top < parent.top) - container.scrollTop -= parent.top - self.top; - else if (self.bottom > parent.bottom) - container.scrollTop += self.bottom - parent.bottom; +function selectByChar(view, forward) { + return extendSel(view, range => view.moveByChar(range, forward)); } - -const MaxOptions = 300; -// Used to pick a preferred option when two options with the same -// label occur in the result. -function score(option) { - return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + - (option.type ? 1 : 0); +/** +Move the selection head one character to the left, while leaving +the anchor in place. +*/ +const selectCharLeft = view$1 => selectByChar(view$1, view$1.textDirection != view.Direction.LTR); +/** +Move the selection head one character to the right. +*/ +const selectCharRight = view$1 => selectByChar(view$1, view$1.textDirection == view.Direction.LTR); +/** +Move the selection head one character forward. +*/ +const selectCharForward = view => selectByChar(view, true); +/** +Move the selection head one character backward. +*/ +const selectCharBackward = view => selectByChar(view, false); +function selectByGroup(view, forward) { + return extendSel(view, range => view.moveByGroup(range, forward)); } -function sortOptions(active, state) { - let options = [], i = 0; - for (let a of active) - if (a.hasResult()) { - if (a.result.filter === false) { - for (let option of a.result.options) - options.push(new Option(option, a, [1e9 - i++])); - } - else { - let matcher = new FuzzyMatcher(state.sliceDoc(a.from, a.to)), match; - for (let option of a.result.options) - if (match = matcher.match(option.label)) { - if (option.boost != null) - match[0] += option.boost; - options.push(new Option(option, a, match)); - } - } - } - options.sort(cmpOption); - let result = [], prev = null; - for (let opt of options.sort(cmpOption)) { - if (result.length == MaxOptions) - break; - if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail || - prev.type != opt.completion.type || prev.apply != opt.completion.apply) - result.push(opt); - else if (score(opt.completion) > score(prev)) - result[result.length - 1] = opt; - prev = opt.completion; - } - return result; +/** +Move the selection head one [group](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) to +the left. +*/ +const selectGroupLeft = view$1 => selectByGroup(view$1, view$1.textDirection != view.Direction.LTR); +/** +Move the selection head one group to the right. +*/ +const selectGroupRight = view$1 => selectByGroup(view$1, view$1.textDirection == view.Direction.LTR); +/** +Move the selection head one group forward. +*/ +const selectGroupForward = view => selectByGroup(view, true); +/** +Move the selection head one group backward. +*/ +const selectGroupBackward = view => selectByGroup(view, false); +function selectBySubword(view, forward) { + return extendSel(view, range => moveBySubword(view, range, forward)); } -class CompletionDialog { - constructor(options, attrs, tooltip, timestamp, selected) { - this.options = options; - this.attrs = attrs; - this.tooltip = tooltip; - this.timestamp = timestamp; - this.selected = selected; - } - setSelected(selected, id) { - return selected == this.selected || selected >= this.options.length ? this - : new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected); - } - static build(active, state, id, prev, conf) { - let options = sortOptions(active, state); - if (!options.length) - return null; - let selected = 0; - if (prev && prev.selected) { - let selectedValue = prev.options[prev.selected].completion; - for (let i = 0; i < options.length && !selected; i++) { - if (options[i].completion == selectedValue) - selected = i; - } +/** +Move the selection head one group or camel-case subword forward. +*/ +const selectSubwordForward = view => selectBySubword(view, true); +/** +Move the selection head one group or subword backward. +*/ +const selectSubwordBackward = view => selectBySubword(view, false); +/** +Move the selection head over the next syntactic element to the left. +*/ +const selectSyntaxLeft = view$1 => extendSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection != view.Direction.LTR)); +/** +Move the selection head over the next syntactic element to the right. +*/ +const selectSyntaxRight = view$1 => extendSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection == view.Direction.LTR)); +function selectByLine(view, forward) { + return extendSel(view, range => view.moveVertically(range, forward)); +} +/** +Move the selection head one line up. +*/ +const selectLineUp = view => selectByLine(view, false); +/** +Move the selection head one line down. +*/ +const selectLineDown = view => selectByLine(view, true); +function selectByPage(view, forward) { + return extendSel(view, range => view.moveVertically(range, forward, view.dom.clientHeight)); +} +/** +Move the selection head one page up. +*/ +const selectPageUp = view => selectByPage(view, false); +/** +Move the selection head one page down. +*/ +const selectPageDown = view => selectByPage(view, true); +/** +Move the selection head to the next line boundary. +*/ +const selectLineBoundaryForward = view => extendSel(view, range => moveByLineBoundary(view, range, true)); +/** +Move the selection head to the previous line boundary. +*/ +const selectLineBoundaryBackward = view => extendSel(view, range => moveByLineBoundary(view, range, false)); +/** +Move the selection head to the start of the line. +*/ +const selectLineStart = view => extendSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).from)); +/** +Move the selection head to the end of the line. +*/ +const selectLineEnd = view => extendSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).to)); +/** +Move the selection to the start of the document. +*/ +const cursorDocStart = ({ state, dispatch }) => { + dispatch(setSel(state, { anchor: 0 })); + return true; +}; +/** +Move the selection to the end of the document. +*/ +const cursorDocEnd = ({ state, dispatch }) => { + dispatch(setSel(state, { anchor: state.doc.length })); + return true; +}; +/** +Move the selection head to the start of the document. +*/ +const selectDocStart = ({ state, dispatch }) => { + dispatch(setSel(state, { anchor: state.selection.main.anchor, head: 0 })); + return true; +}; +/** +Move the selection head to the end of the document. +*/ +const selectDocEnd = ({ state, dispatch }) => { + dispatch(setSel(state, { anchor: state.selection.main.anchor, head: state.doc.length })); + return true; +}; +/** +Select the entire document. +*/ +const selectAll = ({ state, dispatch }) => { + dispatch(state.update({ selection: { anchor: 0, head: state.doc.length }, userEvent: "select" })); + return true; +}; +/** +Expand the selection to cover entire lines. +*/ +const selectLine = ({ state: state$1, dispatch }) => { + let ranges = selectedLineBlocks(state$1).map(({ from, to }) => state.EditorSelection.range(from, Math.min(to + 1, state$1.doc.length))); + dispatch(state$1.update({ selection: state.EditorSelection.create(ranges), userEvent: "select" })); + return true; +}; +/** +Select the next syntactic construct that is larger than the +selection. Note that this will only work insofar as the language +[provider](https://codemirror.net/6/docs/ref/#language.language) you use builds up a full +syntax tree. +*/ +const selectParentSyntax = ({ state: state$1, dispatch }) => { + let selection = updateSel(state$1.selection, range => { + var _a; + let context = language.syntaxTree(state$1).resolveInner(range.head, 1); + while (!((context.from < range.from && context.to >= range.to) || + (context.to > range.to && context.from <= range.from) || + !((_a = context.parent) === null || _a === void 0 ? void 0 : _a.parent))) + context = context.parent; + return state.EditorSelection.range(context.to, context.from); + }); + dispatch(setSel(state$1, selection)); + return true; +}; +/** +Simplify the current selection. When multiple ranges are selected, +reduce it to its main range. Otherwise, if the selection is +non-empty, convert it to a cursor selection. +*/ +const simplifySelection = ({ state: state$1, dispatch }) => { + let cur = state$1.selection, selection = null; + if (cur.ranges.length > 1) + selection = state.EditorSelection.create([cur.main]); + else if (!cur.main.empty) + selection = state.EditorSelection.create([state.EditorSelection.cursor(cur.main.head)]); + if (!selection) + return false; + dispatch(setSel(state$1, selection)); + return true; +}; +function deleteBy({ state: state$1, dispatch }, by) { + if (state$1.readOnly) + return false; + let event = "delete.selection"; + let changes = state$1.changeByRange(range => { + let { from, to } = range; + if (from == to) { + let towards = by(from); + if (towards < from) + event = "delete.backward"; + else if (towards > from) + event = "delete.forward"; + from = Math.min(from, towards); + to = Math.max(to, towards); } - return new CompletionDialog(options, makeAttrs(id, selected), { - pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8), - create: completionTooltip(completionState), - above: conf.aboveCursor, - }, prev ? prev.timestamp : Date.now(), selected); - } - map(changes) { - return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected); - } + return from == to ? { range } : { changes: { from, to }, range: state.EditorSelection.cursor(from) }; + }); + if (changes.changes.empty) + return false; + dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: event })); + return true; } -class CompletionState { - constructor(active, id, open) { - this.active = active; - this.id = id; - this.open = open; - } - static start() { - return new CompletionState(none, "cm-ac-" + Math.floor(Math.random() * 2e6).toString(36), null); - } - update(tr) { - let { state } = tr, conf = state.facet(completionConfig); - let sources = conf.override || - state.languageDataAt("autocomplete", cur(state)).map(asSource); - let active = sources.map(source => { - let value = this.active.find(s => s.source == source) || - new ActiveSource(source, this.active.some(a => a.state != 0 /* Inactive */) ? 1 /* Pending */ : 0 /* Inactive */); - return value.update(tr, conf); - }); - if (active.length == this.active.length && active.every((a, i) => a == this.active[i])) - active = this.active; - let open = tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || - !sameResults(active, this.active) ? CompletionDialog.build(active, state, this.id, this.open, conf) - : this.open && tr.docChanged ? this.open.map(tr.changes) : this.open; - if (!open && active.every(a => a.state != 1 /* Pending */) && active.some(a => a.hasResult())) - active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* Inactive */) : a); - for (let effect of tr.effects) - if (effect.is(setSelectedEffect)) - open = open && open.setSelected(effect.value, this.id); - return active == this.active && open == this.open ? this : new CompletionState(active, this.id, open); - } - get tooltip() { return this.open ? this.open.tooltip : null; } - get attrs() { return this.open ? this.open.attrs : baseAttrs; } +function skipAtomic(target, pos, forward) { + if (target instanceof view.EditorView) + for (let ranges of target.pluginField(view.PluginField.atomicRanges)) + ranges.between(pos, pos, (from, to) => { + if (from < pos && to > pos) + pos = forward ? to : from; + }); + return pos; } -function sameResults(a, b) { - if (a == b) - return true; - for (let iA = 0, iB = 0;;) { - while (iA < a.length && !a[iA].hasResult) - iA++; - while (iB < b.length && !b[iB].hasResult) - iB++; - let endA = iA == a.length, endB = iB == b.length; - if (endA || endB) - return endA == endB; - if (a[iA++].result != b[iB++].result) - return false; +const deleteByChar = (target, forward) => deleteBy(target, pos => { + let { state } = target, line = state.doc.lineAt(pos), before, targetPos; + if (!forward && pos > line.from && pos < line.from + 200 && + !/[^ \t]/.test(before = line.text.slice(0, pos - line.from))) { + if (before[before.length - 1] == "\t") + return pos - 1; + let col = text.countColumn(before, state.tabSize), drop = col % language.getIndentUnit(state) || language.getIndentUnit(state); + for (let i = 0; i < drop && before[before.length - 1 - i] == " "; i++) + pos--; + targetPos = pos; } -} -const baseAttrs = { - "aria-autocomplete": "list", - "aria-expanded": "false" -}; -function makeAttrs(id, selected) { - return { - "aria-autocomplete": "list", - "aria-expanded": "true", - "aria-activedescendant": id + "-" + selected, - "aria-controls": id - }; -} -const none = []; -function cmpOption(a, b) { - let dScore = b.match[0] - a.match[0]; - if (dScore) - return dScore; - return a.completion.label.localeCompare(b.completion.label); -} -function getUserEvent(tr) { - return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null; -} -class ActiveSource { - constructor(source, state, explicitPos = -1) { - this.source = source; - this.state = state; - this.explicitPos = explicitPos; + else { + targetPos = text.findClusterBreak(line.text, pos - line.from, forward) + line.from; + if (targetPos == pos && line.number != (forward ? state.doc.lines : 1)) + targetPos += forward ? 1 : -1; } - hasResult() { return false; } - update(tr, conf) { - let event = getUserEvent(tr), value = this; - if (event) - value = value.handleUserEvent(tr, event, conf); - else if (tr.docChanged) - value = value.handleChange(tr); - else if (tr.selection && value.state != 0 /* Inactive */) - value = new ActiveSource(value.source, 0 /* Inactive */); - for (let effect of tr.effects) { - if (effect.is(startCompletionEffect)) - value = new ActiveSource(value.source, 1 /* Pending */, effect.value ? cur(tr.state) : -1); - else if (effect.is(closeCompletionEffect)) - value = new ActiveSource(value.source, 0 /* Inactive */); - else if (effect.is(setActiveEffect)) - for (let active of effect.value) - if (active.source == value.source) - value = active; + return skipAtomic(target, targetPos, forward); +}); +/** +Delete the selection, or, for cursor selections, the character +before the cursor. +*/ +const deleteCharBackward = view => deleteByChar(view, false); +/** +Delete the selection or the character after the cursor. +*/ +const deleteCharForward = view => deleteByChar(view, true); +const deleteByGroup = (target, forward) => deleteBy(target, start => { + let pos = start, { state } = target, line = state.doc.lineAt(pos); + let categorize = state.charCategorizer(pos); + for (let cat = null;;) { + if (pos == (forward ? line.to : line.from)) { + if (pos == start && line.number != (forward ? state.doc.lines : 1)) + pos += forward ? 1 : -1; + break; } - return value; - } - handleUserEvent(tr, type, conf) { - return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* Pending */); + let next = text.findClusterBreak(line.text, pos - line.from, forward) + line.from; + let nextChar = line.text.slice(Math.min(pos, next) - line.from, Math.max(pos, next) - line.from); + let nextCat = categorize(nextChar); + if (cat != null && nextCat != cat) + break; + if (nextChar != " " || pos != start) + cat = nextCat; + pos = next; } - handleChange(tr) { - return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes); + return skipAtomic(target, pos, forward); +}); +/** +Delete the selection or backward until the end of the next +[group](https://codemirror.net/6/docs/ref/#view.EditorView.moveByGroup), only skipping groups of +whitespace when they consist of a single space. +*/ +const deleteGroupBackward = target => deleteByGroup(target, false); +/** +Delete the selection or forward until the end of the next group. +*/ +const deleteGroupForward = target => deleteByGroup(target, true); +/** +Delete the selection, or, if it is a cursor selection, delete to +the end of the line. If the cursor is directly at the end of the +line, delete the line break after it. +*/ +const deleteToLineEnd = view => deleteBy(view, pos => { + let lineEnd = view.lineBlockAt(pos).to; + return skipAtomic(view, pos < lineEnd ? lineEnd : Math.min(view.state.doc.length, pos + 1), true); +}); +/** +Delete the selection, or, if it is a cursor selection, delete to +the start of the line. If the cursor is directly at the start of the +line, delete the line break before it. +*/ +const deleteToLineStart = view => deleteBy(view, pos => { + let lineStart = view.lineBlockAt(pos).from; + return skipAtomic(view, pos > lineStart ? lineStart : Math.max(0, pos - 1), false); +}); +/** +Delete all whitespace directly before a line end from the +document. +*/ +const deleteTrailingWhitespace = ({ state, dispatch }) => { + if (state.readOnly) + return false; + let changes = []; + for (let pos = 0, prev = "", iter = state.doc.iter();;) { + iter.next(); + if (iter.lineBreak || iter.done) { + let trailing = prev.search(/\s+$/); + if (trailing > -1) + changes.push({ from: pos - (prev.length - trailing), to: pos }); + if (iter.done) + break; + prev = ""; + } + else { + prev = iter.value; + } + pos += iter.value.length; } - map(changes) { - return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos)); + if (!changes.length) + return false; + dispatch(state.update({ changes, userEvent: "delete" })); + return true; +}; +/** +Replace each selection range with a line break, leaving the cursor +on the line before the break. +*/ +const splitLine = ({ state: state$1, dispatch }) => { + if (state$1.readOnly) + return false; + let changes = state$1.changeByRange(range => { + return { changes: { from: range.from, to: range.to, insert: text.Text.of(["", ""]) }, + range: state.EditorSelection.cursor(range.from) }; + }); + dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: "input" })); + return true; +}; +/** +Flip the characters before and after the cursor(s). +*/ +const transposeChars = ({ state: state$1, dispatch }) => { + if (state$1.readOnly) + return false; + let changes = state$1.changeByRange(range => { + if (!range.empty || range.from == 0 || range.from == state$1.doc.length) + return { range }; + let pos = range.from, line = state$1.doc.lineAt(pos); + let from = pos == line.from ? pos - 1 : text.findClusterBreak(line.text, pos - line.from, false) + line.from; + let to = pos == line.to ? pos + 1 : text.findClusterBreak(line.text, pos - line.from, true) + line.from; + return { changes: { from, to, insert: state$1.doc.slice(pos, to).append(state$1.doc.slice(from, pos)) }, + range: state.EditorSelection.cursor(to) }; + }); + if (changes.changes.empty) + return false; + dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: "move.character" })); + return true; +}; +function selectedLineBlocks(state) { + let blocks = [], upto = -1; + for (let range of state.selection.ranges) { + let startLine = state.doc.lineAt(range.from), endLine = state.doc.lineAt(range.to); + if (!range.empty && range.to == endLine.from) + endLine = state.doc.lineAt(range.to - 1); + if (upto >= startLine.number) { + let prev = blocks[blocks.length - 1]; + prev.to = endLine.to; + prev.ranges.push(range); + } + else { + blocks.push({ from: startLine.from, to: endLine.to, ranges: [range] }); + } + upto = endLine.number + 1; } + return blocks; } -class ActiveResult extends ActiveSource { - constructor(source, explicitPos, result, from, to, span) { - super(source, 2 /* Result */, explicitPos); - this.result = result; - this.from = from; - this.to = to; - this.span = span; - } - hasResult() { return true; } - handleUserEvent(tr, type, conf) { - let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1); - let pos = cur(tr.state); - if ((this.explicitPos > -1 ? pos < from : pos <= from) || pos > to) - return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */); - let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos); - if (this.span && (from == to || this.span.test(tr.state.sliceDoc(from, to)))) - return new ActiveResult(this.source, explicitPos, this.result, from, to, this.span); - return new ActiveSource(this.source, 1 /* Pending */, explicitPos); - } - handleChange(tr) { - return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes); +function moveLine(state$1, dispatch, forward) { + if (state$1.readOnly) + return false; + let changes = [], ranges = []; + for (let block of selectedLineBlocks(state$1)) { + if (forward ? block.to == state$1.doc.length : block.from == 0) + continue; + let nextLine = state$1.doc.lineAt(forward ? block.to + 1 : block.from - 1); + let size = nextLine.length + 1; + if (forward) { + changes.push({ from: block.to, to: nextLine.to }, { from: block.from, insert: nextLine.text + state$1.lineBreak }); + for (let r of block.ranges) + ranges.push(state.EditorSelection.range(Math.min(state$1.doc.length, r.anchor + size), Math.min(state$1.doc.length, r.head + size))); + } + else { + changes.push({ from: nextLine.from, to: block.from }, { from: block.to, insert: state$1.lineBreak + nextLine.text }); + for (let r of block.ranges) + ranges.push(state.EditorSelection.range(r.anchor - size, r.head - size)); + } } - map(mapping) { - return mapping.empty ? this : - new ActiveResult(this.source, this.explicitPos < 0 ? -1 : mapping.mapPos(this.explicitPos), this.result, mapping.mapPos(this.from), mapping.mapPos(this.to, 1), this.span); + if (!changes.length) + return false; + dispatch(state$1.update({ + changes, + scrollIntoView: true, + selection: state.EditorSelection.create(ranges, state$1.selection.mainIndex), + userEvent: "move.line" + })); + return true; +} +/** +Move the selected lines up one line. +*/ +const moveLineUp = ({ state, dispatch }) => moveLine(state, dispatch, false); +/** +Move the selected lines down one line. +*/ +const moveLineDown = ({ state, dispatch }) => moveLine(state, dispatch, true); +function copyLine(state, dispatch, forward) { + if (state.readOnly) + return false; + let changes = []; + for (let block of selectedLineBlocks(state)) { + if (forward) + changes.push({ from: block.from, insert: state.doc.slice(block.from, block.to) + state.lineBreak }); + else + changes.push({ from: block.to, insert: state.lineBreak + state.doc.slice(block.from, block.to) }); } + dispatch(state.update({ changes, scrollIntoView: true, userEvent: "input.copyline" })); + return true; } -const startCompletionEffect = state.StateEffect.define(); -const closeCompletionEffect = state.StateEffect.define(); -const setActiveEffect = state.StateEffect.define({ - map(sources, mapping) { return sources.map(s => s.map(mapping)); } -}); -const setSelectedEffect = state.StateEffect.define(); -const completionState = state.StateField.define({ - create() { return CompletionState.start(); }, - update(value, tr) { return value.update(tr); }, - provide: f => [ - tooltip.showTooltip.from(f, val => val.tooltip), - view.EditorView.contentAttributes.from(f, state => state.attrs) - ] -}); - -const CompletionInteractMargin = 75; /** -Returns a command that moves the completion selection forward or -backward by the given amount. +Create a copy of the selected lines. Keep the selection in the top copy. */ -function moveCompletionSelection(forward, by = "option") { - return (view) => { - let cState = view.state.field(completionState, false); - if (!cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin) +const copyLineUp = ({ state, dispatch }) => copyLine(state, dispatch, false); +/** +Create a copy of the selected lines. Keep the selection in the bottom copy. +*/ +const copyLineDown = ({ state, dispatch }) => copyLine(state, dispatch, true); +/** +Delete selected lines. +*/ +const deleteLine = view => { + if (view.state.readOnly) + return false; + let { state } = view, changes = state.changes(selectedLineBlocks(state).map(({ from, to }) => { + if (from > 0) + from--; + else if (to < state.doc.length) + to++; + return { from, to }; + })); + let selection = updateSel(state.selection, range => view.moveVertically(range, true)).map(changes); + view.dispatch({ changes, selection, scrollIntoView: true, userEvent: "delete.line" }); + return true; +}; +/** +Replace the selection with a newline. +*/ +const insertNewline = ({ state, dispatch }) => { + dispatch(state.update(state.replaceSelection(state.lineBreak), { scrollIntoView: true, userEvent: "input" })); + return true; +}; +function isBetweenBrackets(state, pos) { + if (/\(\)|\[\]|\{\}/.test(state.sliceDoc(pos - 1, pos + 1))) + return { from: pos, to: pos }; + let context = language.syntaxTree(state).resolveInner(pos); + let before = context.childBefore(pos), after = context.childAfter(pos), closedBy; + if (before && after && before.to <= pos && after.from >= pos && + (closedBy = before.type.prop(common.NodeProp.closedBy)) && closedBy.indexOf(after.name) > -1 && + state.doc.lineAt(before.to).from == state.doc.lineAt(after.from).from) + return { from: before.to, to: after.from }; + return null; +} +/** +Replace the selection with a newline and indent the newly created +line(s). If the current line consists only of whitespace, this +will also delete that whitespace. When the cursor is between +matching brackets, an additional newline will be inserted after +the cursor. +*/ +const insertNewlineAndIndent = newlineAndIndent(false); +/** +Create a blank, indented line below the current line. +*/ +const insertBlankLine = newlineAndIndent(true); +function newlineAndIndent(atEof) { + return ({ state: state$1, dispatch }) => { + if (state$1.readOnly) return false; - let step = 1, tooltip$1; - if (by == "page" && (tooltip$1 = tooltip.getTooltip(view, cState.open.tooltip))) - step = Math.max(2, Math.floor(tooltip$1.dom.offsetHeight / - tooltip$1.dom.querySelector("li").offsetHeight) - 1); - let selected = cState.open.selected + step * (forward ? 1 : -1), { length } = cState.open.options; - if (selected < 0) - selected = by == "page" ? 0 : length - 1; - else if (selected >= length) - selected = by == "page" ? length - 1 : 0; - view.dispatch({ effects: setSelectedEffect.of(selected) }); + let changes = state$1.changeByRange(range => { + let { from, to } = range, line = state$1.doc.lineAt(from); + let explode = !atEof && from == to && isBetweenBrackets(state$1, from); + if (atEof) + from = to = (to <= line.to ? line : state$1.doc.lineAt(to)).to; + let cx = new language.IndentContext(state$1, { simulateBreak: from, simulateDoubleBreak: !!explode }); + let indent = language.getIndentation(cx, from); + if (indent == null) + indent = /^\s*/.exec(state$1.doc.lineAt(from).text)[0].length; + while (to < line.to && /\s/.test(line.text[to - line.from])) + to++; + if (explode) + ({ from, to } = explode); + else if (from > line.from && from < line.from + 100 && !/\S/.test(line.text.slice(0, from))) + from = line.from; + let insert = ["", language.indentString(state$1, indent)]; + if (explode) + insert.push(language.indentString(state$1, cx.lineIndent(line.from, -1))); + return { changes: { from, to, insert: text.Text.of(insert) }, + range: state.EditorSelection.cursor(from + 1 + insert[1].length) }; + }); + dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: "input" })); return true; }; } +function changeBySelectedLine(state$1, f) { + let atLine = -1; + return state$1.changeByRange(range => { + let changes = []; + for (let pos = range.from; pos <= range.to;) { + let line = state$1.doc.lineAt(pos); + if (line.number > atLine && (range.empty || range.to > line.from)) { + f(line, changes, range); + atLine = line.number; + } + pos = line.to + 1; + } + let changeSet = state$1.changes(changes); + return { changes, + range: state.EditorSelection.range(changeSet.mapPos(range.anchor, 1), changeSet.mapPos(range.head, 1)) }; + }); +} /** -Accept the current completion. +Auto-indent the selected lines. This uses the [indentation service +facet](https://codemirror.net/6/docs/ref/#language.indentService) as source for auto-indent +information. */ -const acceptCompletion = (view) => { - let cState = view.state.field(completionState, false); - if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin) +const indentSelection = ({ state, dispatch }) => { + if (state.readOnly) return false; - applyCompletion(view, cState.open.options[cState.open.selected]); + let updated = Object.create(null); + let context = new language.IndentContext(state, { overrideIndentation: start => { + let found = updated[start]; + return found == null ? -1 : found; + } }); + let changes = changeBySelectedLine(state, (line, changes, range) => { + let indent = language.getIndentation(context, line.from); + if (indent == null) + return; + if (!/\S/.test(line.text)) + indent = 0; + let cur = /^\s*/.exec(line.text)[0]; + let norm = language.indentString(state, indent); + if (cur != norm || range.from < line.from + cur.length) { + updated[line.from] = indent; + changes.push({ from: line.from, to: line.from + cur.length, insert: norm }); + } + }); + if (!changes.changes.empty) + dispatch(state.update(changes, { userEvent: "indent" })); + return true; +}; +/** +Add a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation to all selected +lines. +*/ +const indentMore = ({ state, dispatch }) => { + if (state.readOnly) + return false; + dispatch(state.update(changeBySelectedLine(state, (line, changes) => { + changes.push({ from: line.from, insert: state.facet(language.indentUnit) }); + }), { userEvent: "input.indent" })); return true; }; /** -Explicitly start autocompletion. +Remove a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation from all +selected lines. */ -const startCompletion = (view) => { - let cState = view.state.field(completionState, false); - if (!cState) +const indentLess = ({ state, dispatch }) => { + if (state.readOnly) return false; - view.dispatch({ effects: startCompletionEffect.of(true) }); + dispatch(state.update(changeBySelectedLine(state, (line, changes) => { + let space = /^\s*/.exec(line.text)[0]; + if (!space) + return; + let col = text.countColumn(space, state.tabSize), keep = 0; + let insert = language.indentString(state, Math.max(0, col - language.getIndentUnit(state))); + while (keep < space.length && keep < insert.length && space.charCodeAt(keep) == insert.charCodeAt(keep)) + keep++; + changes.push({ from: line.from + keep, to: line.from + space.length, insert: insert.slice(keep) }); + }), { userEvent: "delete.dedent" })); return true; }; /** -Close the currently active completion. +Insert a tab character at the cursor or, if something is selected, +use [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) to indent the entire +selection. */ -const closeCompletion = (view) => { - let cState = view.state.field(completionState, false); - if (!cState || !cState.active.some(a => a.state != 0 /* Inactive */)) - return false; - view.dispatch({ effects: closeCompletionEffect.of(null) }); +const insertTab = ({ state, dispatch }) => { + if (state.selection.ranges.some(r => !r.empty)) + return indentMore({ state, dispatch }); + dispatch(state.update(state.replaceSelection("\t"), { scrollIntoView: true, userEvent: "input" })); return true; }; -class RunningQuery { - constructor(active, context) { - this.active = active; - this.context = context; - this.time = Date.now(); - this.updates = []; - // Note that 'undefined' means 'not done yet', whereas 'null' means - // 'query returned null'. - this.done = undefined; - } -} -const DebounceTime = 50, MaxUpdateCount = 50, MinAbortTime = 1000; -const completionPlugin = view.ViewPlugin.fromClass(class { - constructor(view) { - this.view = view; - this.debounceUpdate = -1; - this.running = []; - this.debounceAccept = -1; - this.composing = 0 /* None */; - for (let active of view.state.field(completionState).active) - if (active.state == 1 /* Pending */) - this.startQuery(active); - } - update(update) { - let cState = update.state.field(completionState); - if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState) - return; - let doesReset = update.transactions.some(tr => { - return (tr.selection || tr.docChanged) && !getUserEvent(tr); - }); - for (let i = 0; i < this.running.length; i++) { - let query = this.running[i]; - if (doesReset || - query.updates.length + update.transactions.length > MaxUpdateCount && query.time - Date.now() > MinAbortTime) { - for (let handler of query.context.abortListeners) { - try { - handler(); - } - catch (e) { - view.logException(this.view.state, e); - } - } - query.context.abortListeners = null; - this.running.splice(i--, 1); - } - else { - query.updates.push(...update.transactions); - } - } - if (this.debounceUpdate > -1) - clearTimeout(this.debounceUpdate); - this.debounceUpdate = cState.active.some(a => a.state == 1 /* Pending */ && !this.running.some(q => q.active.source == a.source)) - ? setTimeout(() => this.startUpdate(), DebounceTime) : -1; - if (this.composing != 0 /* None */) - for (let tr of update.transactions) { - if (getUserEvent(tr) == "input") - this.composing = 2 /* Changed */; - else if (this.composing == 2 /* Changed */ && tr.selection) - this.composing = 3 /* ChangedAndMoved */; - } - } - startUpdate() { - this.debounceUpdate = -1; - let { state } = this.view, cState = state.field(completionState); - for (let active of cState.active) { - if (active.state == 1 /* Pending */ && !this.running.some(r => r.active.source == active.source)) - this.startQuery(active); - } - } - startQuery(active) { - let { state } = this.view, pos = cur(state); - let context = new CompletionContext(state, pos, active.explicitPos == pos); - let pending = new RunningQuery(active, context); - this.running.push(pending); - Promise.resolve(active.source(context)).then(result => { - if (!pending.context.aborted) { - pending.done = result || null; - this.scheduleAccept(); - } - }, err => { - this.view.dispatch({ effects: closeCompletionEffect.of(null) }); - view.logException(this.view.state, err); - }); - } - scheduleAccept() { - if (this.running.every(q => q.done !== undefined)) - this.accept(); - else if (this.debounceAccept < 0) - this.debounceAccept = setTimeout(() => this.accept(), DebounceTime); - } - // For each finished query in this.running, try to create a result - // or, if appropriate, restart the query. - accept() { - var _a; - if (this.debounceAccept > -1) - clearTimeout(this.debounceAccept); - this.debounceAccept = -1; - let updated = []; - let conf = this.view.state.facet(completionConfig); - for (let i = 0; i < this.running.length; i++) { - let query = this.running[i]; - if (query.done === undefined) - continue; - this.running.splice(i--, 1); - if (query.done) { - let active = new ActiveResult(query.active.source, query.active.explicitPos, query.done, query.done.from, (_a = query.done.to) !== null && _a !== void 0 ? _a : cur(query.updates.length ? query.updates[0].startState : this.view.state), query.done.span && query.done.filter !== false ? ensureAnchor(query.done.span, true) : null); - // Replay the transactions that happened since the start of - // the request and see if that preserves the result - for (let tr of query.updates) - active = active.update(tr, conf); - if (active.hasResult()) { - updated.push(active); - continue; - } - } - let current = this.view.state.field(completionState).active.find(a => a.source == query.active.source); - if (current && current.state == 1 /* Pending */) { - if (query.done == null) { - // Explicitly failed. Should clear the pending status if it - // hasn't been re-set in the meantime. - let active = new ActiveSource(query.active.source, 0 /* Inactive */); - for (let tr of query.updates) - active = active.update(tr, conf); - if (active.state != 1 /* Pending */) - updated.push(active); - } - else { - // Cleared by subsequent transactions. Restart. - this.startQuery(current); - } - } - } - if (updated.length) - this.view.dispatch({ effects: setActiveEffect.of(updated) }); - } -}, { - eventHandlers: { - compositionstart() { - this.composing = 1 /* Started */; - }, - compositionend() { - if (this.composing == 3 /* ChangedAndMoved */) { - // Safari fires compositionend events synchronously, possibly - // from inside an update, so dispatch asynchronously to avoid reentrancy - setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20); - } - this.composing = 0 /* None */; - } - } -}); +/** +Array of key bindings containing the Emacs-style bindings that are +available on macOS by default. -const baseTheme = view.EditorView.baseTheme({ - ".cm-tooltip.cm-tooltip-autocomplete": { - "& > ul": { - fontFamily: "monospace", - whiteSpace: "nowrap", - overflow: "hidden auto", - maxWidth_fallback: "700px", - maxWidth: "min(700px, 95vw)", - minWidth: "250px", - maxHeight: "10em", - listStyle: "none", - margin: 0, - padding: 0, - "& > li": { - overflowX: "hidden", - textOverflow: "ellipsis", - cursor: "pointer", - padding: "1px 3px", - lineHeight: 1.2 - }, - } - }, - "&light .cm-tooltip-autocomplete ul li[aria-selected]": { - background: "#17c", - color: "white", - }, - "&dark .cm-tooltip-autocomplete ul li[aria-selected]": { - background: "#347", - color: "white", - }, - ".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": { - content: '"···"', - opacity: 0.5, - display: "block", - textAlign: "center" - }, - ".cm-tooltip.cm-completionInfo": { - position: "absolute", - padding: "3px 9px", - width: "max-content", - maxWidth: "300px", - }, - ".cm-completionInfo.cm-completionInfo-left": { right: "100%" }, - ".cm-completionInfo.cm-completionInfo-right": { left: "100%" }, - "&light .cm-snippetField": { backgroundColor: "#00000022" }, - "&dark .cm-snippetField": { backgroundColor: "#ffffff22" }, - ".cm-snippetFieldPosition": { - verticalAlign: "text-top", - width: 0, - height: "1.15em", - margin: "0 -0.7px -.7em", - borderLeft: "1.4px dotted #888" - }, - ".cm-completionMatchedText": { - textDecoration: "underline" - }, - ".cm-completionDetail": { - marginLeft: "0.5em", - fontStyle: "italic" - }, - ".cm-completionIcon": { - fontSize: "90%", - width: ".8em", - display: "inline-block", - textAlign: "center", - paddingRight: ".6em", - opacity: "0.6" - }, - ".cm-completionIcon-function, .cm-completionIcon-method": { - "&:after": { content: "'ƒ'" } - }, - ".cm-completionIcon-class": { - "&:after": { content: "'○'" } - }, - ".cm-completionIcon-interface": { - "&:after": { content: "'◌'" } - }, - ".cm-completionIcon-variable": { - "&:after": { content: "'𝑥'" } - }, - ".cm-completionIcon-constant": { - "&:after": { content: "'𝐶'" } - }, - ".cm-completionIcon-type": { - "&:after": { content: "'𝑡'" } - }, - ".cm-completionIcon-enum": { - "&:after": { content: "'∪'" } - }, - ".cm-completionIcon-property": { - "&:after": { content: "'□'" } - }, - ".cm-completionIcon-keyword": { - "&:after": { content: "'🔑\uFE0E'" } // Disable emoji rendering - }, - ".cm-completionIcon-namespace": { - "&:after": { content: "'▢'" } - }, - ".cm-completionIcon-text": { - "&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" } - } -}); + - Ctrl-b: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift) + - Ctrl-f: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift) + - Ctrl-p: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift) + - Ctrl-n: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift) + - Ctrl-a: [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift) + - Ctrl-e: [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift) + - Ctrl-d: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward) + - Ctrl-h: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward) + - Ctrl-k: [`deleteToLineEnd`](https://codemirror.net/6/docs/ref/#commands.deleteToLineEnd) + - Ctrl-Alt-h: [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward) + - Ctrl-o: [`splitLine`](https://codemirror.net/6/docs/ref/#commands.splitLine) + - Ctrl-t: [`transposeChars`](https://codemirror.net/6/docs/ref/#commands.transposeChars) + - Ctrl-v: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) + - Alt-v: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) +*/ +const emacsStyleKeymap = [ + { key: "Ctrl-b", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, + { key: "Ctrl-f", run: cursorCharRight, shift: selectCharRight }, + { key: "Ctrl-p", run: cursorLineUp, shift: selectLineUp }, + { key: "Ctrl-n", run: cursorLineDown, shift: selectLineDown }, + { key: "Ctrl-a", run: cursorLineStart, shift: selectLineStart }, + { key: "Ctrl-e", run: cursorLineEnd, shift: selectLineEnd }, + { key: "Ctrl-d", run: deleteCharForward }, + { key: "Ctrl-h", run: deleteCharBackward }, + { key: "Ctrl-k", run: deleteToLineEnd }, + { key: "Ctrl-Alt-h", run: deleteGroupBackward }, + { key: "Ctrl-o", run: splitLine }, + { key: "Ctrl-t", run: transposeChars }, + { key: "Ctrl-v", run: cursorPageDown }, + { key: "Alt-v", run: cursorPageUp }, +]; +/** +An array of key bindings closely sticking to platform-standard or +widely used bindings. (This includes the bindings from +[`emacsStyleKeymap`](https://codemirror.net/6/docs/ref/#commands.emacsStyleKeymap), with their `key` +property changed to `mac`.) + + - ArrowLeft: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift) + - ArrowRight: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift) + - Ctrl-ArrowLeft (Alt-ArrowLeft on macOS): [`cursorGroupLeft`](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) ([`selectGroupLeft`](https://codemirror.net/6/docs/ref/#commands.selectGroupLeft) with Shift) + - Ctrl-ArrowRight (Alt-ArrowRight on macOS): [`cursorGroupRight`](https://codemirror.net/6/docs/ref/#commands.cursorGroupRight) ([`selectGroupRight`](https://codemirror.net/6/docs/ref/#commands.selectGroupRight) with Shift) + - Cmd-ArrowLeft (on macOS): [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift) + - Cmd-ArrowRight (on macOS): [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift) + - ArrowUp: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift) + - ArrowDown: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift) + - Cmd-ArrowUp (on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift) + - Cmd-ArrowDown (on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift) + - Ctrl-ArrowUp (on macOS): [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift) + - Ctrl-ArrowDown (on macOS): [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift) + - PageUp: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift) + - PageDown: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift) + - Home: [`cursorLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryBackward) ([`selectLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryBackward) with Shift) + - End: [`cursorLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryForward) ([`selectLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryForward) with Shift) + - Ctrl-Home (Cmd-Home on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift) + - Ctrl-End (Cmd-Home on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift) + - Enter: [`insertNewlineAndIndent`](https://codemirror.net/6/docs/ref/#commands.insertNewlineAndIndent) + - Ctrl-a (Cmd-a on macOS): [`selectAll`](https://codemirror.net/6/docs/ref/#commands.selectAll) + - Backspace: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward) + - Delete: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward) + - Ctrl-Backspace (Alt-Backspace on macOS): [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward) + - Ctrl-Delete (Alt-Delete on macOS): [`deleteGroupForward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupForward) + - Cmd-Backspace (macOS): [`deleteToLineStart`](https://codemirror.net/6/docs/ref/#commands.deleteToLineStart). + - Cmd-Delete (macOS): [`deleteToLineEnd`](https://codemirror.net/6/docs/ref/#commands.deleteToLineEnd). +*/ +const standardKeymap = [ + { key: "ArrowLeft", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, + { key: "Mod-ArrowLeft", mac: "Alt-ArrowLeft", run: cursorGroupLeft, shift: selectGroupLeft }, + { mac: "Cmd-ArrowLeft", run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward }, + { key: "ArrowRight", run: cursorCharRight, shift: selectCharRight, preventDefault: true }, + { key: "Mod-ArrowRight", mac: "Alt-ArrowRight", run: cursorGroupRight, shift: selectGroupRight }, + { mac: "Cmd-ArrowRight", run: cursorLineBoundaryForward, shift: selectLineBoundaryForward }, + { key: "ArrowUp", run: cursorLineUp, shift: selectLineUp, preventDefault: true }, + { mac: "Cmd-ArrowUp", run: cursorDocStart, shift: selectDocStart }, + { mac: "Ctrl-ArrowUp", run: cursorPageUp, shift: selectPageUp }, + { key: "ArrowDown", run: cursorLineDown, shift: selectLineDown, preventDefault: true }, + { mac: "Cmd-ArrowDown", run: cursorDocEnd, shift: selectDocEnd }, + { mac: "Ctrl-ArrowDown", run: cursorPageDown, shift: selectPageDown }, + { key: "PageUp", run: cursorPageUp, shift: selectPageUp }, + { key: "PageDown", run: cursorPageDown, shift: selectPageDown }, + { key: "Home", run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward }, + { key: "Mod-Home", run: cursorDocStart, shift: selectDocStart }, + { key: "End", run: cursorLineBoundaryForward, shift: selectLineBoundaryForward }, + { key: "Mod-End", run: cursorDocEnd, shift: selectDocEnd }, + { key: "Enter", run: insertNewlineAndIndent }, + { key: "Mod-a", run: selectAll }, + { key: "Backspace", run: deleteCharBackward, shift: deleteCharBackward }, + { key: "Delete", run: deleteCharForward }, + { key: "Mod-Backspace", mac: "Alt-Backspace", run: deleteGroupBackward }, + { key: "Mod-Delete", mac: "Alt-Delete", run: deleteGroupForward }, + { mac: "Mod-Backspace", run: deleteToLineStart }, + { mac: "Mod-Delete", run: deleteToLineEnd } +].concat(emacsStyleKeymap.map(b => ({ mac: b.key, run: b.run, shift: b.shift }))); +/** +The default keymap. Includes all bindings from +[`standardKeymap`](https://codemirror.net/6/docs/ref/#commands.standardKeymap) plus the following: + +- Alt-ArrowLeft (Ctrl-ArrowLeft on macOS): [`cursorSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxLeft) ([`selectSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxLeft) with Shift) +- Alt-ArrowRight (Ctrl-ArrowRight on macOS): [`cursorSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxRight) ([`selectSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxRight) with Shift) +- Alt-ArrowUp: [`moveLineUp`](https://codemirror.net/6/docs/ref/#commands.moveLineUp) +- Alt-ArrowDown: [`moveLineDown`](https://codemirror.net/6/docs/ref/#commands.moveLineDown) +- Shift-Alt-ArrowUp: [`copyLineUp`](https://codemirror.net/6/docs/ref/#commands.copyLineUp) +- Shift-Alt-ArrowDown: [`copyLineDown`](https://codemirror.net/6/docs/ref/#commands.copyLineDown) +- Escape: [`simplifySelection`](https://codemirror.net/6/docs/ref/#commands.simplifySelection) +- Ctrl-Enter (Comd-Enter on macOS): [`insertBlankLine`](https://codemirror.net/6/docs/ref/#commands.insertBlankLine) +- Alt-l (Ctrl-l on macOS): [`selectLine`](https://codemirror.net/6/docs/ref/#commands.selectLine) +- Ctrl-i (Cmd-i on macOS): [`selectParentSyntax`](https://codemirror.net/6/docs/ref/#commands.selectParentSyntax) +- Ctrl-[ (Cmd-[ on macOS): [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess) +- Ctrl-] (Cmd-] on macOS): [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) +- Ctrl-Alt-\\ (Cmd-Alt-\\ on macOS): [`indentSelection`](https://codemirror.net/6/docs/ref/#commands.indentSelection) +- Shift-Ctrl-k (Shift-Cmd-k on macOS): [`deleteLine`](https://codemirror.net/6/docs/ref/#commands.deleteLine) +- Shift-Ctrl-\\ (Shift-Cmd-\\ on macOS): [`cursorMatchingBracket`](https://codemirror.net/6/docs/ref/#commands.cursorMatchingBracket) +*/ +const defaultKeymap = [ + { key: "Alt-ArrowLeft", mac: "Ctrl-ArrowLeft", run: cursorSyntaxLeft, shift: selectSyntaxLeft }, + { key: "Alt-ArrowRight", mac: "Ctrl-ArrowRight", run: cursorSyntaxRight, shift: selectSyntaxRight }, + { key: "Alt-ArrowUp", run: moveLineUp }, + { key: "Shift-Alt-ArrowUp", run: copyLineUp }, + { key: "Alt-ArrowDown", run: moveLineDown }, + { key: "Shift-Alt-ArrowDown", run: copyLineDown }, + { key: "Escape", run: simplifySelection }, + { key: "Mod-Enter", run: insertBlankLine }, + { key: "Alt-l", mac: "Ctrl-l", run: selectLine }, + { key: "Mod-i", run: selectParentSyntax, preventDefault: true }, + { key: "Mod-[", run: indentLess }, + { key: "Mod-]", run: indentMore }, + { key: "Mod-Alt-\\", run: indentSelection }, + { key: "Shift-Mod-k", run: deleteLine }, + { key: "Shift-Mod-\\", run: cursorMatchingBracket } +].concat(standardKeymap); +/** +A binding that binds Tab to [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) and +Shift-Tab to [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess). +Please see the [Tab example](../../examples/tab/) before using +this. +*/ +const indentWithTab = { key: "Tab", run: indentMore, shift: indentLess }; + +exports.copyLineDown = copyLineDown; +exports.copyLineUp = copyLineUp; +exports.cursorCharBackward = cursorCharBackward; +exports.cursorCharForward = cursorCharForward; +exports.cursorCharLeft = cursorCharLeft; +exports.cursorCharRight = cursorCharRight; +exports.cursorDocEnd = cursorDocEnd; +exports.cursorDocStart = cursorDocStart; +exports.cursorGroupBackward = cursorGroupBackward; +exports.cursorGroupForward = cursorGroupForward; +exports.cursorGroupLeft = cursorGroupLeft; +exports.cursorGroupRight = cursorGroupRight; +exports.cursorLineBoundaryBackward = cursorLineBoundaryBackward; +exports.cursorLineBoundaryForward = cursorLineBoundaryForward; +exports.cursorLineDown = cursorLineDown; +exports.cursorLineEnd = cursorLineEnd; +exports.cursorLineStart = cursorLineStart; +exports.cursorLineUp = cursorLineUp; +exports.cursorMatchingBracket = cursorMatchingBracket; +exports.cursorPageDown = cursorPageDown; +exports.cursorPageUp = cursorPageUp; +exports.cursorSubwordBackward = cursorSubwordBackward; +exports.cursorSubwordForward = cursorSubwordForward; +exports.cursorSyntaxLeft = cursorSyntaxLeft; +exports.cursorSyntaxRight = cursorSyntaxRight; +exports.defaultKeymap = defaultKeymap; +exports.deleteCharBackward = deleteCharBackward; +exports.deleteCharForward = deleteCharForward; +exports.deleteGroupBackward = deleteGroupBackward; +exports.deleteGroupForward = deleteGroupForward; +exports.deleteLine = deleteLine; +exports.deleteToLineEnd = deleteToLineEnd; +exports.deleteToLineStart = deleteToLineStart; +exports.deleteTrailingWhitespace = deleteTrailingWhitespace; +exports.emacsStyleKeymap = emacsStyleKeymap; +exports.indentLess = indentLess; +exports.indentMore = indentMore; +exports.indentSelection = indentSelection; +exports.indentWithTab = indentWithTab; +exports.insertBlankLine = insertBlankLine; +exports.insertNewline = insertNewline; +exports.insertNewlineAndIndent = insertNewlineAndIndent; +exports.insertTab = insertTab; +exports.moveLineDown = moveLineDown; +exports.moveLineUp = moveLineUp; +exports.selectAll = selectAll; +exports.selectCharBackward = selectCharBackward; +exports.selectCharForward = selectCharForward; +exports.selectCharLeft = selectCharLeft; +exports.selectCharRight = selectCharRight; +exports.selectDocEnd = selectDocEnd; +exports.selectDocStart = selectDocStart; +exports.selectGroupBackward = selectGroupBackward; +exports.selectGroupForward = selectGroupForward; +exports.selectGroupLeft = selectGroupLeft; +exports.selectGroupRight = selectGroupRight; +exports.selectLine = selectLine; +exports.selectLineBoundaryBackward = selectLineBoundaryBackward; +exports.selectLineBoundaryForward = selectLineBoundaryForward; +exports.selectLineDown = selectLineDown; +exports.selectLineEnd = selectLineEnd; +exports.selectLineStart = selectLineStart; +exports.selectLineUp = selectLineUp; +exports.selectMatchingBracket = selectMatchingBracket; +exports.selectPageDown = selectPageDown; +exports.selectPageUp = selectPageUp; +exports.selectParentSyntax = selectParentSyntax; +exports.selectSubwordBackward = selectSubwordBackward; +exports.selectSubwordForward = selectSubwordForward; +exports.selectSyntaxLeft = selectSyntaxLeft; +exports.selectSyntaxRight = selectSyntaxRight; +exports.simplifySelection = simplifySelection; +exports.splitLine = splitLine; +exports.standardKeymap = standardKeymap; +exports.transposeChars = transposeChars; + +},{"@codemirror/language":27,"@codemirror/matchbrackets":28,"@codemirror/state":30,"@codemirror/text":31,"@codemirror/view":33,"@lezer/common":34}],25:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var common = require('@lezer/common'); +var styleMod = require('style-mod'); +var view = require('@codemirror/view'); +var state = require('@codemirror/state'); +var language = require('@codemirror/language'); +var rangeset = require('@codemirror/rangeset'); + +let nextTagID = 0; +/** +Highlighting tags are markers that denote a highlighting category. +They are [associated](https://codemirror.net/6/docs/ref/#highlight.styleTags) with parts of a syntax +tree by a language mode, and then mapped to an actual CSS style by +a [highlight style](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle). -class FieldPos { - constructor(field, line, from, to) { - this.field = field; - this.line = line; - this.from = from; - this.to = to; +Because syntax tree node types and highlight styles have to be +able to talk the same language, CodeMirror uses a mostly _closed_ +[vocabulary](https://codemirror.net/6/docs/ref/#highlight.tags) of syntax tags (as opposed to +traditional open string-based systems, which make it hard for +highlighting themes to cover all the tokens produced by the +various languages). + +It _is_ possible to [define](https://codemirror.net/6/docs/ref/#highlight.Tag^define) your own +highlighting tags for system-internal use (where you control both +the language package and the highlighter), but such tags will not +be picked up by regular highlighters (though you can derive them +from standard tags to allow highlighters to fall back to those). +*/ +class Tag { + /** + @internal + */ + constructor( + /** + The set of tags that match this tag, starting with this one + itself, sorted in order of decreasing specificity. @internal + */ + set, + /** + The base unmodified tag that this one is based on, if it's + modified @internal + */ + base, + /** + The modifiers applied to this.base @internal + */ + modified) { + this.set = set; + this.base = base; + this.modified = modified; + /** + @internal + */ + this.id = nextTagID++; } -} -class FieldRange { - constructor(field, from, to) { - this.field = field; - this.from = from; - this.to = to; + /** + Define a new tag. If `parent` is given, the tag is treated as a + sub-tag of that parent, and [highlight + styles](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle) that don't mention this tag + will try to fall back to the parent tag (or grandparent tag, + etc). + */ + static define(parent) { + if (parent === null || parent === void 0 ? void 0 : parent.base) + throw new Error("Can not derive from a modified tag"); + let tag = new Tag([], null, []); + tag.set.push(tag); + if (parent) + for (let t of parent.set) + tag.set.push(t); + return tag; } - map(changes) { - return new FieldRange(this.field, changes.mapPos(this.from, -1), changes.mapPos(this.to, 1)); + /** + Define a tag _modifier_, which is a function that, given a tag, + will return a tag that is a subtag of the original. Applying the + same modifier to a twice tag will return the same value (`m1(t1) + == m1(t1)`) and applying multiple modifiers will, regardless or + order, produce the same tag (`m1(m2(t1)) == m2(m1(t1))`). + + When multiple modifiers are applied to a given base tag, each + smaller set of modifiers is registered as a parent, so that for + example `m1(m2(m3(t1)))` is a subtype of `m1(m2(t1))`, + `m1(m3(t1)`, and so on. + */ + static defineModifier() { + let mod = new Modifier; + return (tag) => { + if (tag.modified.indexOf(mod) > -1) + return tag; + return Modifier.get(tag.base || tag, tag.modified.concat(mod).sort((a, b) => a.id - b.id)); + }; } } -class Snippet { - constructor(lines, fieldPositions) { - this.lines = lines; - this.fieldPositions = fieldPositions; - } - instantiate(state, pos) { - let text = [], lineStart = [pos]; - let lineObj = state.doc.lineAt(pos), baseIndent = /^\s*/.exec(lineObj.text)[0]; - for (let line of this.lines) { - if (text.length) { - let indent = baseIndent, tabs = /^\t*/.exec(line)[0].length; - for (let i = 0; i < tabs; i++) - indent += state.facet(language.indentUnit); - lineStart.push(pos + indent.length - tabs); - line = indent + line.slice(tabs); - } - text.push(line); - pos += line.length + 1; - } - let ranges = this.fieldPositions.map(pos => new FieldRange(pos.field, lineStart[pos.line] + pos.from, lineStart[pos.line] + pos.to)); - return { text, ranges }; +let nextModifierID = 0; +class Modifier { + constructor() { + this.instances = []; + this.id = nextModifierID++; } - static parse(template) { - let fields = []; - let lines = [], positions = [], m; - for (let line of template.split(/\r\n?|\n/)) { - while (m = /[#$]\{(?:(\d+)(?::([^}]*))?|([^}]*))\}/.exec(line)) { - let seq = m[1] ? +m[1] : null, name = m[2] || m[3] || "", found = -1; - for (let i = 0; i < fields.length; i++) { - if (seq != null ? fields[i].seq == seq : name ? fields[i].name == name : false) - found = i; - } - if (found < 0) { - let i = 0; - while (i < fields.length && (seq == null || (fields[i].seq != null && fields[i].seq < seq))) - i++; - fields.splice(i, 0, { seq, name }); - found = i; - for (let pos of positions) - if (pos.field >= found) - pos.field++; - } - positions.push(new FieldPos(found, lines.length, m.index, m.index + name.length)); - line = line.slice(0, m.index) + name + line.slice(m.index + m[0].length); - } - lines.push(line); - } - return new Snippet(lines, positions); + static get(base, mods) { + if (!mods.length) + return base; + let exists = mods[0].instances.find(t => t.base == base && sameArray(mods, t.modified)); + if (exists) + return exists; + let set = [], tag = new Tag(set, base, mods); + for (let m of mods) + m.instances.push(tag); + let configs = permute(mods); + for (let parent of base.set) + for (let config of configs) + set.push(Modifier.get(parent, config)); + return tag; } } -let fieldMarker = view.Decoration.widget({ widget: new class extends view.WidgetType { - toDOM() { - let span = document.createElement("span"); - span.className = "cm-snippetFieldPosition"; - return span; - } - ignoreEvent() { return false; } - } }); -let fieldRange = view.Decoration.mark({ class: "cm-snippetField" }); -class ActiveSnippet { - constructor(ranges, active) { - this.ranges = ranges; - this.active = active; - this.deco = view.Decoration.set(ranges.map(r => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to))); - } - map(changes) { - return new ActiveSnippet(this.ranges.map(r => r.map(changes)), this.active); - } - selectionInsideField(sel) { - return sel.ranges.every(range => this.ranges.some(r => r.field == this.active && r.from <= range.from && r.to >= range.to)); - } +function sameArray(a, b) { + return a.length == b.length && a.every((x, i) => x == b[i]); } -const setActive = state.StateEffect.define({ - map(value, changes) { return value && value.map(changes); } -}); -const moveToField = state.StateEffect.define(); -const snippetState = state.StateField.define({ - create() { return null; }, - update(value, tr) { - for (let effect of tr.effects) { - if (effect.is(setActive)) - return effect.value; - if (effect.is(moveToField) && value) - return new ActiveSnippet(value.ranges, effect.value); - } - if (value && tr.docChanged) - value = value.map(tr.changes); - if (value && tr.selection && !value.selectionInsideField(tr.selection)) - value = null; - return value; - }, - provide: f => view.EditorView.decorations.from(f, val => val ? val.deco : view.Decoration.none) -}); -function fieldSelection(ranges, field) { - return state.EditorSelection.create(ranges.filter(r => r.field == field).map(r => state.EditorSelection.range(r.from, r.to))); +function permute(array) { + let result = [array]; + for (let i = 0; i < array.length; i++) { + for (let a of permute(array.slice(0, i).concat(array.slice(i + 1)))) + result.push(a); + } + return result; } /** -Convert a snippet template to a function that can apply it. -Snippets are written using syntax like this: +This function is used to add a set of tags to a language syntax +via +[`LRParser.configure`](https://lezer.codemirror.net/docs/ref#lr.LRParser.configure). - "for (let ${index} = 0; ${index} < ${end}; ${index}++) {\n\t${}\n}" +The argument object maps node selectors to [highlighting +tags](https://codemirror.net/6/docs/ref/#highlight.Tag) or arrays of tags. -Each `${}` placeholder (you may also use `#{}`) indicates a field -that the user can fill in. Its name, if any, will be the default -content for the field. +Node selectors may hold one or more (space-separated) node paths. +Such a path can be a [node +name](https://lezer.codemirror.net/docs/ref#common.NodeType.name), +or multiple node names (or `*` wildcards) separated by slash +characters, as in `"Block/Declaration/VariableName"`. Such a path +matches the final node but only if its direct parent nodes are the +other nodes mentioned. A `*` in such a path matches any parent, +but only a single level—wildcards that match multiple parents +aren't supported, both for efficiency reasons and because Lezer +trees make it rather hard to reason about what they would match.) -When the snippet is activated by calling the returned function, -the code is inserted at the given position. Newlines in the -template are indented by the indentation of the start line, plus -one [indent unit](https://codemirror.net/6/docs/ref/#language.indentUnit) per tab character after -the newline. +A path can be ended with `/...` to indicate that the tag assigned +to the node should also apply to all child nodes, even if they +match their own style (by default, only the innermost style is +used). -On activation, (all instances of) the first field are selected. -The user can move between fields with Tab and Shift-Tab as long as -the fields are active. Moving to the last field or moving the -cursor out of the current field deactivates the fields. +When a path ends in `!`, as in `Attribute!`, no further matching +happens for the node's child nodes, and the entire node gets the +given style. -The order of fields defaults to textual order, but you can add -numbers to placeholders (`${1}` or `${1:defaultText}`) to provide -a custom order. +In this notation, node names that contain `/`, `!`, `*`, or `...` +must be quoted as JSON strings. + +For example: + +```javascript +parser.withProps( + styleTags({ + // Style Number and BigNumber nodes + "Number BigNumber": tags.number, + // Style Escape nodes whose parent is String + "String/Escape": tags.escape, + // Style anything inside Attributes nodes + "Attributes!": tags.meta, + // Add a style to all content inside Italic nodes + "Italic/...": tags.emphasis, + // Style InvalidString nodes as both `string` and `invalid` + "InvalidString": [tags.string, tags.invalid], + // Style the node named "/" as punctuation + '"/"': tags.punctuation + }) +) +``` */ -function snippet(template) { - let snippet = Snippet.parse(template); - return (editor, _completion, from, to) => { - let { text, ranges } = snippet.instantiate(editor.state, from); - let spec = { changes: { from, to, insert: state.Text.of(text) } }; - if (ranges.length) - spec.selection = fieldSelection(ranges, 0); - if (ranges.length > 1) { - let active = new ActiveSnippet(ranges, 0); - let effects = spec.effects = [setActive.of(active)]; - if (editor.state.field(snippetState, false) === undefined) - effects.push(state.StateEffect.appendConfig.of([snippetState, addSnippetKeymap, snippetPointerHandler, baseTheme])); +function styleTags(spec) { + let byName = Object.create(null); + for (let prop in spec) { + let tags = spec[prop]; + if (!Array.isArray(tags)) + tags = [tags]; + for (let part of prop.split(" ")) + if (part) { + let pieces = [], mode = 2 /* Normal */, rest = part; + for (let pos = 0;;) { + if (rest == "..." && pos > 0 && pos + 3 == part.length) { + mode = 1 /* Inherit */; + break; + } + let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest); + if (!m) + throw new RangeError("Invalid path: " + part); + pieces.push(m[0] == "*" ? null : m[0][0] == '"' ? JSON.parse(m[0]) : m[0]); + pos += m[0].length; + if (pos == part.length) + break; + let next = part[pos++]; + if (pos == part.length && next == "!") { + mode = 0 /* Opaque */; + break; + } + if (next != "/") + throw new RangeError("Invalid path: " + part); + rest = part.slice(pos); + } + let last = pieces.length - 1, inner = pieces[last]; + if (!inner) + throw new RangeError("Invalid path: " + part); + let rule = new Rule(tags, mode, last > 0 ? pieces.slice(0, last) : null); + byName[inner] = rule.sort(byName[inner]); + } + } + return ruleNodeProp.add(byName); +} +const ruleNodeProp = new common.NodeProp(); +const highlightStyle = state.Facet.define({ + combine(stylings) { return stylings.length ? HighlightStyle.combinedMatch(stylings) : null; } +}); +const fallbackHighlightStyle = state.Facet.define({ + combine(values) { return values.length ? values[0].match : null; } +}); +function getHighlightStyle(state) { + return state.facet(highlightStyle) || state.facet(fallbackHighlightStyle); +} +class Rule { + constructor(tags, mode, context, next) { + this.tags = tags; + this.mode = mode; + this.context = context; + this.next = next; + } + sort(other) { + if (!other || other.depth < this.depth) { + this.next = other; + return this; } - editor.dispatch(editor.state.update(spec)); - }; + other.next = this.sort(other.next); + return other; + } + get depth() { return this.context ? this.context.length : 0; } } -function moveField(dir) { - return ({ state, dispatch }) => { - let active = state.field(snippetState, false); - if (!active || dir < 0 && active.active == 0) - return false; - let next = active.active + dir, last = dir > 0 && !active.ranges.some(r => r.field == next + dir); - dispatch(state.update({ - selection: fieldSelection(active.ranges, next), - effects: setActive.of(last ? null : new ActiveSnippet(active.ranges, next)) - })); - return true; - }; +/** +A highlight style associates CSS styles with higlighting +[tags](https://codemirror.net/6/docs/ref/#highlight.Tag). +*/ +class HighlightStyle { + constructor(spec, options) { + this.map = Object.create(null); + let modSpec; + function def(spec) { + let cls = styleMod.StyleModule.newName(); + (modSpec || (modSpec = Object.create(null)))["." + cls] = spec; + return cls; + } + this.all = typeof options.all == "string" ? options.all : options.all ? def(options.all) : null; + for (let style of spec) { + let cls = (style.class || def(Object.assign({}, style, { tag: null }))) + + (this.all ? " " + this.all : ""); + let tags = style.tag; + if (!Array.isArray(tags)) + this.map[tags.id] = cls; + else + for (let tag of tags) + this.map[tag.id] = cls; + } + this.module = modSpec ? new styleMod.StyleModule(modSpec) : null; + this.scope = options.scope || null; + this.match = this.match.bind(this); + let ext = [treeHighlighter]; + if (this.module) + ext.push(view.EditorView.styleModule.of(this.module)); + this.extension = ext.concat(highlightStyle.of(this)); + this.fallback = ext.concat(fallbackHighlightStyle.of(this)); + } + /** + Returns the CSS class associated with the given tag, if any. + This method is bound to the instance by the constructor. + */ + match(tag, scope) { + if (this.scope && scope != this.scope) + return null; + for (let t of tag.set) { + let match = this.map[t.id]; + if (match !== undefined) { + if (t != tag) + this.map[tag.id] = match; + return match; + } + } + return this.map[tag.id] = this.all; + } + /** + Combines an array of highlight styles into a single match + function that returns all of the classes assigned by the styles + for a given tag. + */ + static combinedMatch(styles) { + if (styles.length == 1) + return styles[0].match; + let cache = styles.some(s => s.scope) ? undefined : Object.create(null); + return (tag, scope) => { + let cached = cache && cache[tag.id]; + if (cached !== undefined) + return cached; + let result = null; + for (let style of styles) { + let value = style.match(tag, scope); + if (value) + result = result ? result + " " + value : value; + } + if (cache) + cache[tag.id] = result; + return result; + }; + } + /** + Create a highlighter style that associates the given styles to + the given tags. The spec must be objects that hold a style tag + or array of tags in their `tag` property, and either a single + `class` property providing a static CSS class (for highlighters + like [`classHighlightStyle`](https://codemirror.net/6/docs/ref/#highlight.classHighlightStyle) + that rely on external styling), or a + [`style-mod`](https://github.com/marijnh/style-mod#documentation)-style + set of CSS properties (which define the styling for those tags). + + The CSS rules created for a highlighter will be emitted in the + order of the spec's properties. That means that for elements that + have multiple tags associated with them, styles defined further + down in the list will have a higher CSS precedence than styles + defined earlier. + */ + static define(specs, options) { + return new HighlightStyle(specs, options || {}); + } + /** + Returns the CSS classes (if any) that the highlight styles + active in the given state would assign to the given a style + [tag](https://codemirror.net/6/docs/ref/#highlight.Tag) and (optional) language + [scope](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle^define^options.scope). + */ + static get(state, tag, scope) { + let style = getHighlightStyle(state); + return style && style(tag, scope || common.NodeType.none); + } } /** -A command that clears the active snippet, if any. +Run the tree highlighter over the given tree. */ -const clearSnippet = ({ state, dispatch }) => { - let active = state.field(snippetState, false); - if (!active) - return false; - dispatch(state.update({ effects: setActive.of(null) })); - return true; -}; +function highlightTree(tree, /** -Move to the next snippet field, if available. +Get the CSS classes used to style a given [tag](https://codemirror.net/6/docs/ref/#highlight.Tag), +or `null` if it isn't styled. (You'll often want to pass a +highlight style's [`match`](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle.match) +method here.) */ -const nextSnippetField = moveField(1); +getStyle, /** -Move to the previous snippet field, if available. +Assign styling to a region of the text. Will be called, in order +of position, for any ranges where more than zero classes apply. +`classes` is a space separated string of CSS classes. */ -const prevSnippetField = moveField(-1); -const defaultSnippetKeymap = [ - { key: "Tab", run: nextSnippetField, shift: prevSnippetField }, - { key: "Escape", run: clearSnippet } -]; +putStyle, /** -A facet that can be used to configure the key bindings used by -snippets. The default binds Tab to -[`nextSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.nextSnippetField), Shift-Tab to -[`prevSnippetField`](https://codemirror.net/6/docs/ref/#autocomplete.prevSnippetField), and Escape -to [`clearSnippet`](https://codemirror.net/6/docs/ref/#autocomplete.clearSnippet). +The start of the range to highlight. */ -const snippetKeymap = state.Facet.define({ - combine(maps) { return maps.length ? maps[0] : defaultSnippetKeymap; } -}); -const addSnippetKeymap = state.Prec.highest(view.keymap.compute([snippetKeymap], state => state.facet(snippetKeymap))); +from = 0, /** -Create a completion from a snippet. Returns an object with the -properties from `completion`, plus an `apply` function that -applies the snippet. +The end of the range. */ -function snippetCompletion(template, completion) { - return Object.assign(Object.assign({}, completion), { apply: snippet(template) }); +to = tree.length) { + highlightTreeRange(tree, from, to, getStyle, putStyle); } -const snippetPointerHandler = view.EditorView.domEventHandlers({ - mousedown(event, view) { - let active = view.state.field(snippetState, false), pos; - if (!active || (pos = view.posAtCoords({ x: event.clientX, y: event.clientY })) == null) - return false; - let match = active.ranges.find(r => r.from <= pos && r.to >= pos); - if (!match || match.field == active.active) - return false; - view.dispatch({ - selection: fieldSelection(active.ranges, match.field), - effects: setActive.of(active.ranges.some(r => r.field > match.field) ? new ActiveSnippet(active.ranges, match.field) : null) - }); - return true; +class TreeHighlighter { + constructor(view) { + this.markCache = Object.create(null); + this.tree = language.syntaxTree(view.state); + this.decorations = this.buildDeco(view, getHighlightStyle(view.state)); } -}); - -function wordRE(wordChars) { - let escaped = wordChars.replace(/[\\[.+*?(){|^$]/g, "\\$&"); - try { - return new RegExp(`[\\p{Alphabetic}\\p{Number}_${escaped}]+`, "ug"); + update(update) { + let tree = language.syntaxTree(update.state), style = getHighlightStyle(update.state); + let styleChange = style != update.startState.facet(highlightStyle); + if (tree.length < update.view.viewport.to && !styleChange && tree.type == this.tree.type) { + this.decorations = this.decorations.map(update.changes); + } + else if (tree != this.tree || update.viewportChanged || styleChange) { + this.tree = tree; + this.decorations = this.buildDeco(update.view, style); + } } - catch (_a) { - return new RegExp(`[\w${escaped}]`, "g"); + buildDeco(view$1, match) { + if (!match || !this.tree.length) + return view.Decoration.none; + let builder = new rangeset.RangeSetBuilder(); + for (let { from, to } of view$1.visibleRanges) { + highlightTreeRange(this.tree, from, to, match, (from, to, style) => { + builder.add(from, to, this.markCache[style] || (this.markCache[style] = view.Decoration.mark({ class: style }))); + }); + } + return builder.finish(); } } -function mapRE(re, f) { - return new RegExp(f(re.source), re.unicode ? "u" : ""); -} -const wordCaches = Object.create(null); -function wordCache(wordChars) { - return wordCaches[wordChars] || (wordCaches[wordChars] = new WeakMap); -} -function storeWords(doc, wordRE, result, seen, ignoreAt) { - for (let lines = doc.iterLines(), pos = 0; !lines.next().done;) { - let { value } = lines, m; - wordRE.lastIndex = 0; - while (m = wordRE.exec(value)) { - if (!seen[m[0]] && pos + m.index != ignoreAt) { - result.push({ type: "text", label: m[0] }); - seen[m[0]] = true; - if (result.length >= 2000 /* MaxList */) - return; - } +// This extension installs a highlighter that highlights based on the +// syntax tree and highlight style. +const treeHighlighter = state.Prec.high(view.ViewPlugin.fromClass(TreeHighlighter, { + decorations: v => v.decorations +})); +const nodeStack = [""]; +class HighlightBuilder { + constructor(at, style, span) { + this.at = at; + this.style = style; + this.span = span; + this.class = ""; + } + startSpan(at, cls) { + if (cls != this.class) { + this.flush(at); + if (at > this.at) + this.at = at; + this.class = cls; } - pos += value.length + 1; } -} -function collectWords(doc, cache, wordRE, to, ignoreAt) { - let big = doc.length >= 1000 /* MinCacheLen */; - let cached = big && cache.get(doc); - if (cached) - return cached; - let result = [], seen = Object.create(null); - if (doc.children) { - let pos = 0; - for (let ch of doc.children) { - if (ch.length >= 1000 /* MinCacheLen */) { - for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) { - if (!seen[c.label]) { - seen[c.label] = true; - result.push(c); + flush(to) { + if (to > this.at && this.class) + this.span(this.at, to, this.class); + } + highlightRange(cursor, from, to, inheritedClass, depth, scope) { + let { type, from: start, to: end } = cursor; + if (start >= to || end <= from) + return; + nodeStack[depth] = type.name; + if (type.isTop) + scope = type; + let cls = inheritedClass; + let rule = type.prop(ruleNodeProp), opaque = false; + while (rule) { + if (!rule.context || matchContext(rule.context, nodeStack, depth)) { + for (let tag of rule.tags) { + let st = this.style(tag, scope); + if (st) { + if (cls) + cls += " "; + cls += st; + if (rule.mode == 1 /* Inherit */) + inheritedClass += (inheritedClass ? " " : "") + st; + else if (rule.mode == 0 /* Opaque */) + opaque = true; } } + break; } - else { - storeWords(ch, wordRE, result, seen, ignoreAt - pos); + rule = rule.next; + } + this.startSpan(cursor.from, cls); + if (opaque) + return; + let mounted = cursor.tree && cursor.tree.prop(common.NodeProp.mounted); + if (mounted && mounted.overlay) { + let inner = cursor.node.enter(mounted.overlay[0].from + start, 1); + let hasChild = cursor.firstChild(); + for (let i = 0, pos = start;; i++) { + let next = i < mounted.overlay.length ? mounted.overlay[i] : null; + let nextPos = next ? next.from + start : end; + let rangeFrom = Math.max(from, pos), rangeTo = Math.min(to, nextPos); + if (rangeFrom < rangeTo && hasChild) { + while (cursor.from < rangeTo) { + this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, depth + 1, scope); + this.startSpan(Math.min(to, cursor.to), cls); + if (cursor.to >= nextPos || !cursor.nextSibling()) + break; + } + } + if (!next || nextPos > to) + break; + pos = next.to + start; + if (pos > from) { + this.highlightRange(inner.cursor, Math.max(from, next.from + start), Math.min(to, pos), inheritedClass, depth, mounted.tree.type); + this.startSpan(pos, cls); + } } - pos += ch.length + 1; + if (hasChild) + cursor.parent(); + } + else if (cursor.firstChild()) { + do { + if (cursor.to <= from) + continue; + if (cursor.from >= to) + break; + this.highlightRange(cursor, from, to, inheritedClass, depth + 1, scope); + this.startSpan(Math.min(to, cursor.to), cls); + } while (cursor.nextSibling()); + cursor.parent(); } } - else { - storeWords(doc, wordRE, result, seen, ignoreAt); +} +function highlightTreeRange(tree, from, to, style, span) { + let builder = new HighlightBuilder(from, style, span); + builder.highlightRange(tree.cursor(), from, to, "", 0, tree.type); + builder.flush(to); +} +function matchContext(context, stack, depth) { + if (context.length > depth - 1) + return false; + for (let d = depth - 1, i = context.length - 1; i >= 0; i--, d--) { + let check = context[i]; + if (check && check != stack[d]) + return false; } - if (big && result.length < 2000 /* MaxList */) - cache.set(doc, result); - return result; + return true; } +const t = Tag.define; +const comment = t(), name = t(), typeName = t(name), propertyName = t(name), literal = t(), string = t(literal), number = t(literal), content = t(), heading = t(content), keyword = t(), operator = t(), punctuation = t(), bracket = t(punctuation), meta = t(); /** -A completion source that will scan the document for words (using a -[character categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer)), and -return those as completions. +The default set of highlighting [tags](https://codemirror.net/6/docs/ref/#highlight.Tag^define) used +by regular language packages and themes. + +This collection is heavily biased towards programming languages, +and necessarily incomplete. A full ontology of syntactic +constructs would fill a stack of books, and be impractical to +write themes for. So try to make do with this set. If all else +fails, [open an +issue](https://github.com/codemirror/codemirror.next) to propose a +new tag, or [define](https://codemirror.net/6/docs/ref/#highlight.Tag^define) a local custom tag for +your use case. + +Note that it is not obligatory to always attach the most specific +tag possible to an element—if your grammar can't easily +distinguish a certain type of element (such as a local variable), +it is okay to style it as its more general variant (a variable). + +For tags that extend some parent tag, the documentation links to +the parent. */ -const completeAnyWord = context => { - let wordChars = context.state.languageDataAt("wordChars", context.pos).join(""); - let re = wordRE(wordChars); - let token = context.matchBefore(mapRE(re, s => s + "$")); - if (!token && !context.explicit) - return null; - let from = token ? token.from : context.pos; - let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* Range */, from); - return { from, options, span: mapRE(re, s => "^" + s) }; +const tags = { + /** + A comment. + */ + comment, + /** + A line [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). + */ + lineComment: t(comment), + /** + A block [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). + */ + blockComment: t(comment), + /** + A documentation [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). + */ + docComment: t(comment), + /** + Any kind of identifier. + */ + name, + /** + The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a variable. + */ + variableName: t(name), + /** + A type [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + */ + typeName: typeName, + /** + A tag name (subtag of [`typeName`](https://codemirror.net/6/docs/ref/#highlight.tags.typeName)). + */ + tagName: t(typeName), + /** + A property or field [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + */ + propertyName: propertyName, + /** + An attribute name (subtag of [`propertyName`](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName)). + */ + attributeName: t(propertyName), + /** + The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a class. + */ + className: t(name), + /** + A label [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + */ + labelName: t(name), + /** + A namespace [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). + */ + namespace: t(name), + /** + The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a macro. + */ + macroName: t(name), + /** + A literal value. + */ + literal, + /** + A string [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + */ + string, + /** + A documentation [string](https://codemirror.net/6/docs/ref/#highlight.tags.string). + */ + docString: t(string), + /** + A character literal (subtag of [string](https://codemirror.net/6/docs/ref/#highlight.tags.string)). + */ + character: t(string), + /** + An attribute value (subtag of [string](https://codemirror.net/6/docs/ref/#highlight.tags.string)). + */ + attributeValue: t(string), + /** + A number [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + */ + number, + /** + An integer [number](https://codemirror.net/6/docs/ref/#highlight.tags.number) literal. + */ + integer: t(number), + /** + A floating-point [number](https://codemirror.net/6/docs/ref/#highlight.tags.number) literal. + */ + float: t(number), + /** + A boolean [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + */ + bool: t(literal), + /** + Regular expression [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + */ + regexp: t(literal), + /** + An escape [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal), for example a + backslash escape in a string. + */ + escape: t(literal), + /** + A color [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + */ + color: t(literal), + /** + A URL [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). + */ + url: t(literal), + /** + A language keyword. + */ + keyword, + /** + The [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) for the self or this + object. + */ + self: t(keyword), + /** + The [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) for null. + */ + null: t(keyword), + /** + A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) denoting some atomic value. + */ + atom: t(keyword), + /** + A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that represents a unit. + */ + unit: t(keyword), + /** + A modifier [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword). + */ + modifier: t(keyword), + /** + A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that acts as an operator. + */ + operatorKeyword: t(keyword), + /** + A control-flow related [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword). + */ + controlKeyword: t(keyword), + /** + A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that defines something. + */ + definitionKeyword: t(keyword), + /** + A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) related to defining or + interfacing with modules. + */ + moduleKeyword: t(keyword), + /** + An operator. + */ + operator, + /** + An [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that defines something. + */ + derefOperator: t(operator), + /** + Arithmetic-related [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + */ + arithmeticOperator: t(operator), + /** + Logical [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + */ + logicOperator: t(operator), + /** + Bit [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + */ + bitwiseOperator: t(operator), + /** + Comparison [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + */ + compareOperator: t(operator), + /** + [Operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that updates its operand. + */ + updateOperator: t(operator), + /** + [Operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that defines something. + */ + definitionOperator: t(operator), + /** + Type-related [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + */ + typeOperator: t(operator), + /** + Control-flow [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + */ + controlOperator: t(operator), + /** + Program or markup punctuation. + */ + punctuation, + /** + [Punctuation](https://codemirror.net/6/docs/ref/#highlight.tags.punctuation) that separates + things. + */ + separator: t(punctuation), + /** + Bracket-style [punctuation](https://codemirror.net/6/docs/ref/#highlight.tags.punctuation). + */ + bracket, + /** + Angle [brackets](https://codemirror.net/6/docs/ref/#highlight.tags.bracket) (usually `<` and `>` + tokens). + */ + angleBracket: t(bracket), + /** + Square [brackets](https://codemirror.net/6/docs/ref/#highlight.tags.bracket) (usually `[` and `]` + tokens). + */ + squareBracket: t(bracket), + /** + Parentheses (usually `(` and `)` tokens). Subtag of + [bracket](https://codemirror.net/6/docs/ref/#highlight.tags.bracket). + */ + paren: t(bracket), + /** + Braces (usually `{` and `}` tokens). Subtag of + [bracket](https://codemirror.net/6/docs/ref/#highlight.tags.bracket). + */ + brace: t(bracket), + /** + Content, for example plain text in XML or markup documents. + */ + content, + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a heading. + */ + heading, + /** + A level 1 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + */ + heading1: t(heading), + /** + A level 2 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + */ + heading2: t(heading), + /** + A level 3 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + */ + heading3: t(heading), + /** + A level 4 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + */ + heading4: t(heading), + /** + A level 5 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + */ + heading5: t(heading), + /** + A level 6 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + */ + heading6: t(heading), + /** + A prose separator (such as a horizontal rule). + */ + contentSeparator: t(content), + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a list. + */ + list: t(content), + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a quote. + */ + quote: t(content), + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is emphasized. + */ + emphasis: t(content), + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is styled strong. + */ + strong: t(content), + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is part of a link. + */ + link: t(content), + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is styled as code or + monospace. + */ + monospace: t(content), + /** + [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that has a strike-through + style. + */ + strikethrough: t(content), + /** + Inserted text in a change-tracking format. + */ + inserted: t(), + /** + Deleted text. + */ + deleted: t(), + /** + Changed text. + */ + changed: t(), + /** + An invalid or unsyntactic element. + */ + invalid: t(), + /** + Metadata or meta-instruction. + */ + meta, + /** + [Metadata](https://codemirror.net/6/docs/ref/#highlight.tags.meta) that applies to the entire + document. + */ + documentMeta: t(meta), + /** + [Metadata](https://codemirror.net/6/docs/ref/#highlight.tags.meta) that annotates or adds + attributes to a given syntactic element. + */ + annotation: t(meta), + /** + Processing instruction or preprocessor directive. Subtag of + [meta](https://codemirror.net/6/docs/ref/#highlight.tags.meta). + */ + processingInstruction: t(meta), + /** + [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates that a + given element is being defined. Expected to be used with the + various [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) tags. + */ + definition: Tag.defineModifier(), + /** + [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates that + something is constant. Mostly expected to be used with + [variable names](https://codemirror.net/6/docs/ref/#highlight.tags.variableName). + */ + constant: Tag.defineModifier(), + /** + [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) used to indicate that + a [variable](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) or [property + name](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName) is being called or defined + as a function. + */ + function: Tag.defineModifier(), + /** + [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that can be applied to + [names](https://codemirror.net/6/docs/ref/#highlight.tags.name) to indicate that they belong to + the language's standard environment. + */ + standard: Tag.defineModifier(), + /** + [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates a given + [names](https://codemirror.net/6/docs/ref/#highlight.tags.name) is local to some scope. + */ + local: Tag.defineModifier(), + /** + A generic variant [modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that + can be used to tag language-specific alternative variants of + some common tag. It is recommended for themes to define special + forms of at least the [string](https://codemirror.net/6/docs/ref/#highlight.tags.string) and + [variable name](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) tags, since those + come up a lot. + */ + special: Tag.defineModifier() }; - /** -Returns an extension that enables autocompletion. +A default highlight style (works well with light themes). */ -function autocompletion(config = {}) { - return [ - completionState, - completionConfig.of(config), - completionPlugin, - completionKeymapExt, - baseTheme - ]; -} +const defaultHighlightStyle = HighlightStyle.define([ + { tag: tags.link, + textDecoration: "underline" }, + { tag: tags.heading, + textDecoration: "underline", + fontWeight: "bold" }, + { tag: tags.emphasis, + fontStyle: "italic" }, + { tag: tags.strong, + fontWeight: "bold" }, + { tag: tags.strikethrough, + textDecoration: "line-through" }, + { tag: tags.keyword, + color: "#708" }, + { tag: [tags.atom, tags.bool, tags.url, tags.contentSeparator, tags.labelName], + color: "#219" }, + { tag: [tags.literal, tags.inserted], + color: "#164" }, + { tag: [tags.string, tags.deleted], + color: "#a11" }, + { tag: [tags.regexp, tags.escape, tags.special(tags.string)], + color: "#e40" }, + { tag: tags.definition(tags.variableName), + color: "#00f" }, + { tag: tags.local(tags.variableName), + color: "#30a" }, + { tag: [tags.typeName, tags.namespace], + color: "#085" }, + { tag: tags.className, + color: "#167" }, + { tag: [tags.special(tags.variableName), tags.macroName], + color: "#256" }, + { tag: tags.definition(tags.propertyName), + color: "#00c" }, + { tag: tags.comment, + color: "#940" }, + { tag: tags.meta, + color: "#7a757a" }, + { tag: tags.invalid, + color: "#f00" } +]); /** -Basic keybindings for autocompletion. +This is a highlight style that adds stable, predictable classes to +tokens, for styling with external CSS. - - Ctrl-Space: [`startCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.startCompletion) - - Escape: [`closeCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.closeCompletion) - - ArrowDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true)` - - ArrowUp: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(false)` - - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")` - - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")` - - Enter: [`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion) -*/ -const completionKeymap = [ - { key: "Ctrl-Space", run: startCompletion }, - { key: "Escape", run: closeCompletion }, - { key: "ArrowDown", run: moveCompletionSelection(true) }, - { key: "ArrowUp", run: moveCompletionSelection(false) }, - { key: "PageDown", run: moveCompletionSelection(true, "page") }, - { key: "PageUp", run: moveCompletionSelection(false, "page") }, - { key: "Enter", run: acceptCompletion } -]; -const completionKeymapExt = state.Prec.highest(view.keymap.computeN([completionConfig], state => state.facet(completionConfig).defaultKeymap ? [completionKeymap] : [])); -/** -Get the current completion status. When completions are available, -this will return `"active"`. When completions are pending (in the -process of being queried), this returns `"pending"`. Otherwise, it -returns `null`. -*/ -function completionStatus(state) { - let cState = state.field(completionState, false); - return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending" - : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null; -} -/** -Returns the available completions as an array. -*/ -function currentCompletions(state) { - var _a; - let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open; - return open ? open.options.map(o => o.completion) : []; -} -/** -Return the currently selected completion, if any. +These tags are mapped to their name prefixed with `"cmt-"` (for +example `"cmt-comment"`): + +* [`link`](https://codemirror.net/6/docs/ref/#highlight.tags.link) +* [`heading`](https://codemirror.net/6/docs/ref/#highlight.tags.heading) +* [`emphasis`](https://codemirror.net/6/docs/ref/#highlight.tags.emphasis) +* [`strong`](https://codemirror.net/6/docs/ref/#highlight.tags.strong) +* [`keyword`](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) +* [`atom`](https://codemirror.net/6/docs/ref/#highlight.tags.atom) [`bool`](https://codemirror.net/6/docs/ref/#highlight.tags.bool) +* [`url`](https://codemirror.net/6/docs/ref/#highlight.tags.url) +* [`labelName`](https://codemirror.net/6/docs/ref/#highlight.tags.labelName) +* [`inserted`](https://codemirror.net/6/docs/ref/#highlight.tags.inserted) +* [`deleted`](https://codemirror.net/6/docs/ref/#highlight.tags.deleted) +* [`literal`](https://codemirror.net/6/docs/ref/#highlight.tags.literal) +* [`string`](https://codemirror.net/6/docs/ref/#highlight.tags.string) +* [`number`](https://codemirror.net/6/docs/ref/#highlight.tags.number) +* [`variableName`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) +* [`typeName`](https://codemirror.net/6/docs/ref/#highlight.tags.typeName) +* [`namespace`](https://codemirror.net/6/docs/ref/#highlight.tags.namespace) +* [`className`](https://codemirror.net/6/docs/ref/#highlight.tags.className) +* [`macroName`](https://codemirror.net/6/docs/ref/#highlight.tags.macroName) +* [`propertyName`](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName) +* [`operator`](https://codemirror.net/6/docs/ref/#highlight.tags.operator) +* [`comment`](https://codemirror.net/6/docs/ref/#highlight.tags.comment) +* [`meta`](https://codemirror.net/6/docs/ref/#highlight.tags.meta) +* [`punctuation`](https://codemirror.net/6/docs/ref/#highlight.tags.puncutation) +* [`invalid`](https://codemirror.net/6/docs/ref/#highlight.tags.invalid) + +In addition, these mappings are provided: + +* [`regexp`](https://codemirror.net/6/docs/ref/#highlight.tags.regexp), + [`escape`](https://codemirror.net/6/docs/ref/#highlight.tags.escape), and + [`special`](https://codemirror.net/6/docs/ref/#highlight.tags.special)[`(string)`](https://codemirror.net/6/docs/ref/#highlight.tags.string) + are mapped to `"cmt-string2"` +* [`special`](https://codemirror.net/6/docs/ref/#highlight.tags.special)[`(variableName)`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) + to `"cmt-variableName2"` +* [`local`](https://codemirror.net/6/docs/ref/#highlight.tags.local)[`(variableName)`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) + to `"cmt-variableName cmt-local"` +* [`definition`](https://codemirror.net/6/docs/ref/#highlight.tags.definition)[`(variableName)`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) + to `"cmt-variableName cmt-definition"` +* [`definition`](https://codemirror.net/6/docs/ref/#highlight.tags.definition)[`(propertyName)`](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName) + to `"cmt-propertyName cmt-definition"` */ -function selectedCompletion(state) { - var _a; - let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open; - return open ? open.options[open.selected].completion : null; -} +const classHighlightStyle = HighlightStyle.define([ + { tag: tags.link, class: "cmt-link" }, + { tag: tags.heading, class: "cmt-heading" }, + { tag: tags.emphasis, class: "cmt-emphasis" }, + { tag: tags.strong, class: "cmt-strong" }, + { tag: tags.keyword, class: "cmt-keyword" }, + { tag: tags.atom, class: "cmt-atom" }, + { tag: tags.bool, class: "cmt-bool" }, + { tag: tags.url, class: "cmt-url" }, + { tag: tags.labelName, class: "cmt-labelName" }, + { tag: tags.inserted, class: "cmt-inserted" }, + { tag: tags.deleted, class: "cmt-deleted" }, + { tag: tags.literal, class: "cmt-literal" }, + { tag: tags.string, class: "cmt-string" }, + { tag: tags.number, class: "cmt-number" }, + { tag: [tags.regexp, tags.escape, tags.special(tags.string)], class: "cmt-string2" }, + { tag: tags.variableName, class: "cmt-variableName" }, + { tag: tags.local(tags.variableName), class: "cmt-variableName cmt-local" }, + { tag: tags.definition(tags.variableName), class: "cmt-variableName cmt-definition" }, + { tag: tags.special(tags.variableName), class: "cmt-variableName2" }, + { tag: tags.definition(tags.propertyName), class: "cmt-propertyName cmt-definition" }, + { tag: tags.typeName, class: "cmt-typeName" }, + { tag: tags.namespace, class: "cmt-namespace" }, + { tag: tags.className, class: "cmt-className" }, + { tag: tags.macroName, class: "cmt-macroName" }, + { tag: tags.propertyName, class: "cmt-propertyName" }, + { tag: tags.operator, class: "cmt-operator" }, + { tag: tags.comment, class: "cmt-comment" }, + { tag: tags.meta, class: "cmt-meta" }, + { tag: tags.invalid, class: "cmt-invalid" }, + { tag: tags.punctuation, class: "cmt-punctuation" } +]); -exports.CompletionContext = CompletionContext; -exports.acceptCompletion = acceptCompletion; -exports.autocompletion = autocompletion; -exports.clearSnippet = clearSnippet; -exports.closeCompletion = closeCompletion; -exports.completeAnyWord = completeAnyWord; -exports.completeFromList = completeFromList; -exports.completionKeymap = completionKeymap; -exports.completionStatus = completionStatus; -exports.currentCompletions = currentCompletions; -exports.ifIn = ifIn; -exports.ifNotIn = ifNotIn; -exports.moveCompletionSelection = moveCompletionSelection; -exports.nextSnippetField = nextSnippetField; -exports.pickedCompletion = pickedCompletion; -exports.prevSnippetField = prevSnippetField; -exports.selectedCompletion = selectedCompletion; -exports.snippet = snippet; -exports.snippetCompletion = snippetCompletion; -exports.snippetKeymap = snippetKeymap; -exports.startCompletion = startCompletion; +exports.HighlightStyle = HighlightStyle; +exports.Tag = Tag; +exports.classHighlightStyle = classHighlightStyle; +exports.defaultHighlightStyle = defaultHighlightStyle; +exports.highlightTree = highlightTree; +exports.styleTags = styleTags; +exports.tags = tags; -},{"@codemirror/language":48,"@codemirror/state":51,"@codemirror/text":52,"@codemirror/tooltip":53,"@codemirror/view":54}],45:[function(require,module,exports){ +},{"@codemirror/language":27,"@codemirror/rangeset":29,"@codemirror/state":30,"@codemirror/view":33,"@lezer/common":34,"style-mod":129}],26:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); -var state = require('@codemirror/state'); -var text = require('@codemirror/text'); -var view = require('@codemirror/view'); -var matchbrackets = require('@codemirror/matchbrackets'); +var javascript$1 = require('@lezer/javascript'); var language = require('@codemirror/language'); -var common = require('@lezer/common'); +var highlight = require('@codemirror/highlight'); +var autocomplete = require('@codemirror/autocomplete'); -function updateSel(sel, by) { - return state.EditorSelection.create(sel.ranges.map(by), sel.mainIndex); -} -function setSel(state, selection) { - return state.update({ selection, scrollIntoView: true, userEvent: "select" }); -} -function moveSel({ state, dispatch }, how) { - let selection = updateSel(state.selection, how); - if (selection.eq(state.selection)) - return false; - dispatch(setSel(state, selection)); - return true; -} -function rangeEnd(range, forward) { - return state.EditorSelection.cursor(forward ? range.to : range.from); -} -function cursorByChar(view, forward) { - return moveSel(view, range => range.empty ? view.moveByChar(range, forward) : rangeEnd(range, forward)); -} -/** -Move the selection one character to the left (which is backward in -left-to-right text, forward in right-to-left text). -*/ -const cursorCharLeft = view$1 => cursorByChar(view$1, view$1.textDirection != view.Direction.LTR); -/** -Move the selection one character to the right. -*/ -const cursorCharRight = view$1 => cursorByChar(view$1, view$1.textDirection == view.Direction.LTR); -/** -Move the selection one character forward. -*/ -const cursorCharForward = view => cursorByChar(view, true); -/** -Move the selection one character backward. -*/ -const cursorCharBackward = view => cursorByChar(view, false); -function cursorByGroup(view, forward) { - return moveSel(view, range => range.empty ? view.moveByGroup(range, forward) : rangeEnd(range, forward)); -} -/** -Move the selection to the left across one group of word or -non-word (but also non-space) characters. -*/ -const cursorGroupLeft = view$1 => cursorByGroup(view$1, view$1.textDirection != view.Direction.LTR); -/** -Move the selection one group to the right. -*/ -const cursorGroupRight = view$1 => cursorByGroup(view$1, view$1.textDirection == view.Direction.LTR); -/** -Move the selection one group forward. -*/ -const cursorGroupForward = view => cursorByGroup(view, true); -/** -Move the selection one group backward. -*/ -const cursorGroupBackward = view => cursorByGroup(view, false); -function moveBySubword(view, range, forward) { - let categorize = view.state.charCategorizer(range.from); - return view.moveByChar(range, forward, start => { - let cat = state.CharCategory.Space, pos = range.from; - let done = false, sawUpper = false, sawLower = false; - let step = (next) => { - if (done) - return false; - pos += forward ? next.length : -next.length; - let nextCat = categorize(next), ahead; - if (cat == state.CharCategory.Space) - cat = nextCat; - if (cat != nextCat) - return false; - if (cat == state.CharCategory.Word) { - if (next.toLowerCase() == next) { - if (!forward && sawUpper) - return false; - sawLower = true; - } - else if (sawLower) { - if (forward) - return false; - done = true; - } - else { - if (sawUpper && forward && categorize(ahead = view.state.sliceDoc(pos, pos + 1)) == state.CharCategory.Word && - ahead.toLowerCase() == ahead) - return false; - sawUpper = true; - } - } - return true; - }; - step(start); - return step; - }); -} -function cursorBySubword(view, forward) { - return moveSel(view, range => range.empty ? moveBySubword(view, range, forward) : rangeEnd(range, forward)); -} -/** -Move the selection one group or camel-case subword forward. -*/ -const cursorSubwordForward = view => cursorBySubword(view, true); -/** -Move the selection one group or camel-case subword backward. -*/ -const cursorSubwordBackward = view => cursorBySubword(view, false); -function interestingNode(state, node, bracketProp) { - if (node.type.prop(bracketProp)) - return true; - let len = node.to - node.from; - return len && (len > 2 || /[^\s,.;:]/.test(state.sliceDoc(node.from, node.to))) || node.firstChild; -} -function moveBySyntax(state$1, start, forward) { - let pos = language.syntaxTree(state$1).resolveInner(start.head); - let bracketProp = forward ? common.NodeProp.closedBy : common.NodeProp.openedBy; - // Scan forward through child nodes to see if there's an interesting - // node ahead. - for (let at = start.head;;) { - let next = forward ? pos.childAfter(at) : pos.childBefore(at); - if (!next) - break; - if (interestingNode(state$1, next, bracketProp)) - pos = next; - else - at = forward ? next.to : next.from; - } - let bracket = pos.type.prop(bracketProp), match, newPos; - if (bracket && (match = forward ? matchbrackets.matchBrackets(state$1, pos.from, 1) : matchbrackets.matchBrackets(state$1, pos.to, -1)) && match.matched) - newPos = forward ? match.end.to : match.end.from; - else - newPos = forward ? pos.to : pos.from; - return state.EditorSelection.cursor(newPos, forward ? -1 : 1); -} -/** -Move the cursor over the next syntactic element to the left. -*/ -const cursorSyntaxLeft = view$1 => moveSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection != view.Direction.LTR)); -/** -Move the cursor over the next syntactic element to the right. -*/ -const cursorSyntaxRight = view$1 => moveSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection == view.Direction.LTR)); -function cursorByLine(view, forward) { - return moveSel(view, range => { - if (!range.empty) - return rangeEnd(range, forward); - let moved = view.moveVertically(range, forward); - return moved.head != range.head ? moved : view.moveToLineBoundary(range, forward); - }); -} -/** -Move the selection one line up. -*/ -const cursorLineUp = view => cursorByLine(view, false); -/** -Move the selection one line down. -*/ -const cursorLineDown = view => cursorByLine(view, true); -function cursorByPage(view$1, forward) { - let { state } = view$1, selection = updateSel(state.selection, range => { - return range.empty ? view$1.moveVertically(range, forward, view$1.dom.clientHeight) : rangeEnd(range, forward); - }); - if (selection.eq(state.selection)) - return false; - let startPos = view$1.coordsAtPos(state.selection.main.head); - let scrollRect = view$1.scrollDOM.getBoundingClientRect(); - view$1.dispatch(setSel(state, selection), { - effects: startPos && startPos.top > scrollRect.top && startPos.bottom < scrollRect.bottom - ? view.EditorView.scrollIntoView(selection.main.head, { y: "start", yMargin: startPos.top - scrollRect.top }) - : undefined - }); - return true; -} -/** -Move the selection one page up. -*/ -const cursorPageUp = view => cursorByPage(view, false); -/** -Move the selection one page down. -*/ -const cursorPageDown = view => cursorByPage(view, true); -function moveByLineBoundary(view, start, forward) { - let line = view.lineBlockAt(start.head), moved = view.moveToLineBoundary(start, forward); - if (moved.head == start.head && moved.head != (forward ? line.to : line.from)) - moved = view.moveToLineBoundary(start, forward, false); - if (!forward && moved.head == line.from && line.length) { - let space = /^\s*/.exec(view.state.sliceDoc(line.from, Math.min(line.from + 100, line.to)))[0].length; - if (space && start.head != line.from + space) - moved = state.EditorSelection.cursor(line.from + space); - } - return moved; -} -/** -Move the selection to the next line wrap point, or to the end of -the line if there isn't one left on this line. -*/ -const cursorLineBoundaryForward = view => moveSel(view, range => moveByLineBoundary(view, range, true)); -/** -Move the selection to previous line wrap point, or failing that to -the start of the line. If the line is indented, and the cursor -isn't already at the end of the indentation, this will move to the -end of the indentation instead of the start of the line. -*/ -const cursorLineBoundaryBackward = view => moveSel(view, range => moveByLineBoundary(view, range, false)); -/** -Move the selection to the start of the line. -*/ -const cursorLineStart = view => moveSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).from, 1)); -/** -Move the selection to the end of the line. -*/ -const cursorLineEnd = view => moveSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).to, -1)); -function toMatchingBracket(state$1, dispatch, extend) { - let found = false, selection = updateSel(state$1.selection, range => { - let matching = matchbrackets.matchBrackets(state$1, range.head, -1) - || matchbrackets.matchBrackets(state$1, range.head, 1) - || (range.head > 0 && matchbrackets.matchBrackets(state$1, range.head - 1, 1)) - || (range.head < state$1.doc.length && matchbrackets.matchBrackets(state$1, range.head + 1, -1)); - if (!matching || !matching.end) - return range; - found = true; - let head = matching.start.from == range.head ? matching.end.to : matching.end.from; - return extend ? state.EditorSelection.range(range.anchor, head) : state.EditorSelection.cursor(head); - }); - if (!found) - return false; - dispatch(setSel(state$1, selection)); - return true; -} /** -Move the selection to the bracket matching the one it is currently -on, if any. +A collection of JavaScript-related +[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet). */ -const cursorMatchingBracket = ({ state, dispatch }) => toMatchingBracket(state, dispatch, false); +const snippets = [ + autocomplete.snippetCompletion("function ${name}(${params}) {\n\t${}\n}", { + label: "function", + detail: "definition", + type: "keyword" + }), + autocomplete.snippetCompletion("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n\t${}\n}", { + label: "for", + detail: "loop", + type: "keyword" + }), + autocomplete.snippetCompletion("for (let ${name} of ${collection}) {\n\t${}\n}", { + label: "for", + detail: "of loop", + type: "keyword" + }), + autocomplete.snippetCompletion("try {\n\t${}\n} catch (${error}) {\n\t${}\n}", { + label: "try", + detail: "block", + type: "keyword" + }), + autocomplete.snippetCompletion("class ${name} {\n\tconstructor(${params}) {\n\t\t${}\n\t}\n}", { + label: "class", + detail: "definition", + type: "keyword" + }), + autocomplete.snippetCompletion("import {${names}} from \"${module}\"\n${}", { + label: "import", + detail: "named", + type: "keyword" + }), + autocomplete.snippetCompletion("import ${name} from \"${module}\"\n${}", { + label: "import", + detail: "default", + type: "keyword" + }) +]; + /** -Extend the selection to the bracket matching the one the selection -head is currently on, if any. +A language provider based on the [Lezer JavaScript +parser](https://github.com/lezer-parser/javascript), extended with +highlighting and indentation information. */ -const selectMatchingBracket = ({ state, dispatch }) => toMatchingBracket(state, dispatch, true); -function extendSel(view, how) { - let selection = updateSel(view.state.selection, range => { - let head = how(range); - return state.EditorSelection.range(range.anchor, head.head, head.goalColumn); - }); - if (selection.eq(view.state.selection)) - return false; - view.dispatch(setSel(view.state, selection)); - return true; -} -function selectByChar(view, forward) { - return extendSel(view, range => view.moveByChar(range, forward)); -} +const javascriptLanguage = language.LRLanguage.define({ + parser: javascript$1.parser.configure({ + props: [ + language.indentNodeProp.add({ + IfStatement: language.continuedIndent({ except: /^\s*({|else\b)/ }), + TryStatement: language.continuedIndent({ except: /^\s*({|catch\b|finally\b)/ }), + LabeledStatement: language.flatIndent, + SwitchBody: context => { + let after = context.textAfter, closed = /^\s*\}/.test(after), isCase = /^\s*(case|default)\b/.test(after); + return context.baseIndent + (closed ? 0 : isCase ? 1 : 2) * context.unit; + }, + Block: language.delimitedIndent({ closing: "}" }), + ArrowFunction: cx => cx.baseIndent + cx.unit, + "TemplateString BlockComment": () => -1, + "Statement Property": language.continuedIndent({ except: /^{/ }), + JSXElement(context) { + let closed = /^\s*<\//.test(context.textAfter); + return context.lineIndent(context.node.from) + (closed ? 0 : context.unit); + }, + JSXEscape(context) { + let closed = /\s*\}/.test(context.textAfter); + return context.lineIndent(context.node.from) + (closed ? 0 : context.unit); + }, + "JSXOpenTag JSXSelfClosingTag"(context) { + return context.column(context.node.from) + context.unit; + } + }), + language.foldNodeProp.add({ + "Block ClassBody SwitchBody EnumBody ObjectExpression ArrayExpression": language.foldInside, + BlockComment(tree) { return { from: tree.from + 2, to: tree.to - 2 }; } + }), + highlight.styleTags({ + "get set async static": highlight.tags.modifier, + "for while do if else switch try catch finally return throw break continue default case": highlight.tags.controlKeyword, + "in of await yield void typeof delete instanceof": highlight.tags.operatorKeyword, + "let var const function class extends": highlight.tags.definitionKeyword, + "import export from": highlight.tags.moduleKeyword, + "with debugger as new": highlight.tags.keyword, + TemplateString: highlight.tags.special(highlight.tags.string), + Super: highlight.tags.atom, + BooleanLiteral: highlight.tags.bool, + this: highlight.tags.self, + null: highlight.tags.null, + Star: highlight.tags.modifier, + VariableName: highlight.tags.variableName, + "CallExpression/VariableName TaggedTemplateExpression/VariableName": highlight.tags.function(highlight.tags.variableName), + VariableDefinition: highlight.tags.definition(highlight.tags.variableName), + Label: highlight.tags.labelName, + PropertyName: highlight.tags.propertyName, + PrivatePropertyName: highlight.tags.special(highlight.tags.propertyName), + "CallExpression/MemberExpression/PropertyName": highlight.tags.function(highlight.tags.propertyName), + "FunctionDeclaration/VariableDefinition": highlight.tags.function(highlight.tags.definition(highlight.tags.variableName)), + "ClassDeclaration/VariableDefinition": highlight.tags.definition(highlight.tags.className), + PropertyDefinition: highlight.tags.definition(highlight.tags.propertyName), + PrivatePropertyDefinition: highlight.tags.definition(highlight.tags.special(highlight.tags.propertyName)), + UpdateOp: highlight.tags.updateOperator, + LineComment: highlight.tags.lineComment, + BlockComment: highlight.tags.blockComment, + Number: highlight.tags.number, + String: highlight.tags.string, + ArithOp: highlight.tags.arithmeticOperator, + LogicOp: highlight.tags.logicOperator, + BitOp: highlight.tags.bitwiseOperator, + CompareOp: highlight.tags.compareOperator, + RegExp: highlight.tags.regexp, + Equals: highlight.tags.definitionOperator, + "Arrow : Spread": highlight.tags.punctuation, + "( )": highlight.tags.paren, + "[ ]": highlight.tags.squareBracket, + "{ }": highlight.tags.brace, + ".": highlight.tags.derefOperator, + ", ;": highlight.tags.separator, + TypeName: highlight.tags.typeName, + TypeDefinition: highlight.tags.definition(highlight.tags.typeName), + "type enum interface implements namespace module declare": highlight.tags.definitionKeyword, + "abstract global Privacy readonly override": highlight.tags.modifier, + "is keyof unique infer": highlight.tags.operatorKeyword, + JSXAttributeValue: highlight.tags.attributeValue, + JSXText: highlight.tags.content, + "JSXStartTag JSXStartCloseTag JSXSelfCloseEndTag JSXEndTag": highlight.tags.angleBracket, + "JSXIdentifier JSXNameSpacedName": highlight.tags.tagName, + "JSXAttribute/JSXIdentifier JSXAttribute/JSXNameSpacedName": highlight.tags.attributeName + }) + ] + }), + languageData: { + closeBrackets: { brackets: ["(", "[", "{", "'", '"', "`"] }, + commentTokens: { line: "//", block: { open: "/*", close: "*/" } }, + indentOnInput: /^\s*(?:case |default:|\{|\}|<\/)$/, + wordChars: "$" + } +}); /** -Move the selection head one character to the left, while leaving -the anchor in place. +A language provider for TypeScript. */ -const selectCharLeft = view$1 => selectByChar(view$1, view$1.textDirection != view.Direction.LTR); +const typescriptLanguage = javascriptLanguage.configure({ dialect: "ts" }); /** -Move the selection head one character to the right. +Language provider for JSX. */ -const selectCharRight = view$1 => selectByChar(view$1, view$1.textDirection == view.Direction.LTR); +const jsxLanguage = javascriptLanguage.configure({ dialect: "jsx" }); /** -Move the selection head one character forward. +Language provider for JSX + TypeScript. */ -const selectCharForward = view => selectByChar(view, true); +const tsxLanguage = javascriptLanguage.configure({ dialect: "jsx ts" }); /** -Move the selection head one character backward. +JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets) +completion. */ -const selectCharBackward = view => selectByChar(view, false); -function selectByGroup(view, forward) { - return extendSel(view, range => view.moveByGroup(range, forward)); +function javascript(config = {}) { + let lang = config.jsx ? (config.typescript ? tsxLanguage : jsxLanguage) + : config.typescript ? typescriptLanguage : javascriptLanguage; + return new language.LanguageSupport(lang, javascriptLanguage.data.of({ + autocomplete: autocomplete.ifNotIn(["LineComment", "BlockComment", "String"], autocomplete.completeFromList(snippets)) + })); } + /** -Move the selection head one [group](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) to -the left. -*/ -const selectGroupLeft = view$1 => selectByGroup(view$1, view$1.textDirection != view.Direction.LTR); -/** -Move the selection head one group to the right. -*/ -const selectGroupRight = view$1 => selectByGroup(view$1, view$1.textDirection == view.Direction.LTR); -/** -Move the selection head one group forward. -*/ -const selectGroupForward = view => selectByGroup(view, true); -/** -Move the selection head one group backward. +Connects an [ESLint](https://eslint.org/) linter to CodeMirror's +[lint](https://codemirror.net/6/docs/ref/#lint) integration. `eslint` should be an instance of the +[`Linter`](https://eslint.org/docs/developer-guide/nodejs-api#linter) +class, and `config` an optional ESLint configuration. The return +value of this function can be passed to [`linter`](https://codemirror.net/6/docs/ref/#lint.linter) +to create a JavaScript linting extension. + +Note that ESLint targets node, and is tricky to run in the +browser. The [eslint4b](https://github.com/mysticatea/eslint4b) +and +[eslint4b-prebuilt](https://github.com/marijnh/eslint4b-prebuilt/) +packages may help with that. */ -const selectGroupBackward = view => selectByGroup(view, false); -function selectBySubword(view, forward) { - return extendSel(view, range => moveBySubword(view, range, forward)); +function esLint(eslint, config) { + if (!config) { + config = { + parserOptions: { ecmaVersion: 2019, sourceType: "module" }, + env: { browser: true, node: true, es6: true, es2015: true, es2017: true, es2020: true }, + rules: {} + }; + eslint.getRules().forEach((desc, name) => { + if (desc.meta.docs.recommended) + config.rules[name] = 2; + }); + } + return (view) => { + let { state } = view, found = []; + for (let { from, to } of javascriptLanguage.findRegions(state)) { + let fromLine = state.doc.lineAt(from), offset = { line: fromLine.number - 1, col: from - fromLine.from, pos: from }; + for (let d of eslint.verify(state.sliceDoc(from, to), config)) + found.push(translateDiagnostic(d, state.doc, offset)); + } + return found; + }; } -/** -Move the selection head one group or camel-case subword forward. -*/ -const selectSubwordForward = view => selectBySubword(view, true); -/** -Move the selection head one group or subword backward. -*/ -const selectSubwordBackward = view => selectBySubword(view, false); -/** -Move the selection head over the next syntactic element to the left. -*/ -const selectSyntaxLeft = view$1 => extendSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection != view.Direction.LTR)); -/** -Move the selection head over the next syntactic element to the right. -*/ -const selectSyntaxRight = view$1 => extendSel(view$1, range => moveBySyntax(view$1.state, range, view$1.textDirection == view.Direction.LTR)); -function selectByLine(view, forward) { - return extendSel(view, range => view.moveVertically(range, forward)); +function mapPos(line, col, doc, offset) { + return doc.line(line + offset.line).from + col + (line == 1 ? offset.col - 1 : -1); } -/** -Move the selection head one line up. -*/ -const selectLineUp = view => selectByLine(view, false); -/** -Move the selection head one line down. -*/ -const selectLineDown = view => selectByLine(view, true); -function selectByPage(view, forward) { - return extendSel(view, range => view.moveVertically(range, forward, view.dom.clientHeight)); +function translateDiagnostic(input, doc, offset) { + let start = mapPos(input.line, input.column, doc, offset); + let result = { + from: start, + to: input.endLine != null && input.endColumn != 1 ? mapPos(input.endLine, input.endColumn, doc, offset) : start, + message: input.message, + source: input.ruleId ? "jshint:" + input.ruleId : "jshint", + severity: input.severity == 1 ? "warning" : "error", + }; + if (input.fix) { + let { range, text } = input.fix, from = range[0] + offset.pos - start, to = range[1] + offset.pos - start; + result.actions = [{ + name: "fix", + apply(view, start) { + view.dispatch({ changes: { from: start + from, to: start + to, insert: text }, scrollIntoView: true }); + } + }]; + } + return result; } + +exports.esLint = esLint; +exports.javascript = javascript; +exports.javascriptLanguage = javascriptLanguage; +exports.jsxLanguage = jsxLanguage; +exports.snippets = snippets; +exports.tsxLanguage = tsxLanguage; +exports.typescriptLanguage = typescriptLanguage; + +},{"@codemirror/autocomplete":23,"@codemirror/highlight":25,"@codemirror/language":27,"@lezer/javascript":35}],27:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var common = require('@lezer/common'); +var state = require('@codemirror/state'); +var view = require('@codemirror/view'); +var text = require('@codemirror/text'); + /** -Move the selection head one page up. -*/ -const selectPageUp = view => selectByPage(view, false); -/** -Move the selection head one page down. -*/ -const selectPageDown = view => selectByPage(view, true); -/** -Move the selection head to the next line boundary. -*/ -const selectLineBoundaryForward = view => extendSel(view, range => moveByLineBoundary(view, range, true)); -/** -Move the selection head to the previous line boundary. -*/ -const selectLineBoundaryBackward = view => extendSel(view, range => moveByLineBoundary(view, range, false)); -/** -Move the selection head to the start of the line. -*/ -const selectLineStart = view => extendSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).from)); -/** -Move the selection head to the end of the line. -*/ -const selectLineEnd = view => extendSel(view, range => state.EditorSelection.cursor(view.lineBlockAt(range.head).to)); -/** -Move the selection to the start of the document. -*/ -const cursorDocStart = ({ state, dispatch }) => { - dispatch(setSel(state, { anchor: 0 })); - return true; -}; -/** -Move the selection to the end of the document. -*/ -const cursorDocEnd = ({ state, dispatch }) => { - dispatch(setSel(state, { anchor: state.doc.length })); - return true; -}; -/** -Move the selection head to the start of the document. -*/ -const selectDocStart = ({ state, dispatch }) => { - dispatch(setSel(state, { anchor: state.selection.main.anchor, head: 0 })); - return true; -}; -/** -Move the selection head to the end of the document. -*/ -const selectDocEnd = ({ state, dispatch }) => { - dispatch(setSel(state, { anchor: state.selection.main.anchor, head: state.doc.length })); - return true; -}; -/** -Select the entire document. -*/ -const selectAll = ({ state, dispatch }) => { - dispatch(state.update({ selection: { anchor: 0, head: state.doc.length }, userEvent: "select" })); - return true; -}; -/** -Expand the selection to cover entire lines. +Node prop stored in a grammar's top syntax node to provide the +facet that stores language data for that language. */ -const selectLine = ({ state: state$1, dispatch }) => { - let ranges = selectedLineBlocks(state$1).map(({ from, to }) => state.EditorSelection.range(from, Math.min(to + 1, state$1.doc.length))); - dispatch(state$1.update({ selection: state.EditorSelection.create(ranges), userEvent: "select" })); - return true; -}; +const languageDataProp = new common.NodeProp(); /** -Select the next syntactic construct that is larger than the -selection. Note that this will only work insofar as the language -[provider](https://codemirror.net/6/docs/ref/#language.language) you use builds up a full -syntax tree. +Helper function to define a facet (to be added to the top syntax +node(s) for a language via +[`languageDataProp`](https://codemirror.net/6/docs/ref/#language.languageDataProp)), that will be +used to associate language data with the language. You +probably only need this when subclassing +[`Language`](https://codemirror.net/6/docs/ref/#language.Language). */ -const selectParentSyntax = ({ state: state$1, dispatch }) => { - let selection = updateSel(state$1.selection, range => { - var _a; - let context = language.syntaxTree(state$1).resolveInner(range.head, 1); - while (!((context.from < range.from && context.to >= range.to) || - (context.to > range.to && context.from <= range.from) || - !((_a = context.parent) === null || _a === void 0 ? void 0 : _a.parent))) - context = context.parent; - return state.EditorSelection.range(context.to, context.from); +function defineLanguageFacet(baseData) { + return state.Facet.define({ + combine: baseData ? values => values.concat(baseData) : undefined }); - dispatch(setSel(state$1, selection)); - return true; -}; +} /** -Simplify the current selection. When multiple ranges are selected, -reduce it to its main range. Otherwise, if the selection is -non-empty, convert it to a cursor selection. +A language object manages parsing and per-language +[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is +managed as a [Lezer](https://lezer.codemirror.net) tree. You'll +want to subclass this class for custom parsers, or use the +[`LRLanguage`](https://codemirror.net/6/docs/ref/#language.LRLanguage) or +[`StreamLanguage`](https://codemirror.net/6/docs/ref/#stream-parser.StreamLanguage) abstractions for +[Lezer](https://lezer.codemirror.net/) or stream parsers. */ -const simplifySelection = ({ state: state$1, dispatch }) => { - let cur = state$1.selection, selection = null; - if (cur.ranges.length > 1) - selection = state.EditorSelection.create([cur.main]); - else if (!cur.main.empty) - selection = state.EditorSelection.create([state.EditorSelection.cursor(cur.main.head)]); - if (!selection) - return false; - dispatch(setSel(state$1, selection)); - return true; -}; -function deleteBy({ state: state$1, dispatch }, by) { - if (state$1.readOnly) - return false; - let event = "delete.selection"; - let changes = state$1.changeByRange(range => { - let { from, to } = range; - if (from == to) { - let towards = by(from); - if (towards < from) - event = "delete.backward"; - else if (towards > from) - event = "delete.forward"; - from = Math.min(from, towards); - to = Math.max(to, towards); - } - return from == to ? { range } : { changes: { from, to }, range: state.EditorSelection.cursor(from) }; - }); - if (changes.changes.empty) - return false; - dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: event })); - return true; -} -function skipAtomic(target, pos, forward) { - if (target instanceof view.EditorView) - for (let ranges of target.pluginField(view.PluginField.atomicRanges)) - ranges.between(pos, pos, (from, to) => { - if (from < pos && to > pos) - pos = forward ? to : from; - }); - return pos; -} -const deleteByChar = (target, forward) => deleteBy(target, pos => { - let { state } = target, line = state.doc.lineAt(pos), before, targetPos; - if (!forward && pos > line.from && pos < line.from + 200 && - !/[^ \t]/.test(before = line.text.slice(0, pos - line.from))) { - if (before[before.length - 1] == "\t") - return pos - 1; - let col = text.countColumn(before, state.tabSize), drop = col % language.getIndentUnit(state) || language.getIndentUnit(state); - for (let i = 0; i < drop && before[before.length - 1 - i] == " "; i++) - pos--; - targetPos = pos; +class Language { + /** + Construct a language object. You usually don't need to invoke + this directly. But when you do, make sure you use + [`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet) to create + the first argument. + */ + constructor( + /** + The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) data + facet used for this language. + */ + data, parser, + /** + The node type of the top node of trees produced by this parser. + */ + topNode, extraExtensions = []) { + this.data = data; + this.topNode = topNode; + // Kludge to define EditorState.tree as a debugging helper, + // without the EditorState package actually knowing about + // languages and lezer trees. + if (!state.EditorState.prototype.hasOwnProperty("tree")) + Object.defineProperty(state.EditorState.prototype, "tree", { get() { return syntaxTree(this); } }); + this.parser = parser; + this.extension = [ + language.of(this), + state.EditorState.languageData.of((state, pos, side) => state.facet(languageDataFacetAt(state, pos, side))) + ].concat(extraExtensions); } - else { - targetPos = text.findClusterBreak(line.text, pos - line.from, forward, forward) + line.from; - if (targetPos == pos && line.number != (forward ? state.doc.lines : 1)) - targetPos += forward ? 1 : -1; + /** + Query whether this language is active at the given position. + */ + isActiveAt(state, pos, side = -1) { + return languageDataFacetAt(state, pos, side) == this.data; + } + /** + Find the document regions that were parsed using this language. + The returned regions will _include_ any nested languages rooted + in this language, when those exist. + */ + findRegions(state) { + let lang = state.facet(language); + if ((lang === null || lang === void 0 ? void 0 : lang.data) == this.data) + return [{ from: 0, to: state.doc.length }]; + if (!lang || !lang.allowsNesting) + return []; + let result = []; + let explore = (tree, from) => { + if (tree.prop(languageDataProp) == this.data) { + result.push({ from, to: from + tree.length }); + return; + } + let mount = tree.prop(common.NodeProp.mounted); + if (mount) { + if (mount.tree.prop(languageDataProp) == this.data) { + if (mount.overlay) + for (let r of mount.overlay) + result.push({ from: r.from + from, to: r.to + from }); + else + result.push({ from: from, to: from + tree.length }); + return; + } + else if (mount.overlay) { + let size = result.length; + explore(mount.tree, mount.overlay[0].from + from); + if (result.length > size) + return; + } + } + for (let i = 0; i < tree.children.length; i++) { + let ch = tree.children[i]; + if (ch instanceof common.Tree) + explore(ch, tree.positions[i] + from); + } + }; + explore(syntaxTree(state), 0); + return result; } - return skipAtomic(target, targetPos, forward); -}); + /** + Indicates whether this language allows nested languages. The + default implementation returns true. + */ + get allowsNesting() { return true; } +} /** -Delete the selection, or, for cursor selections, the character -before the cursor. +@internal */ -const deleteCharBackward = view => deleteByChar(view, false); +Language.setState = state.StateEffect.define(); +function languageDataFacetAt(state, pos, side) { + let topLang = state.facet(language); + if (!topLang) + return null; + let facet = topLang.data; + if (topLang.allowsNesting) { + for (let node = syntaxTree(state).topNode; node; node = node.enter(pos, side, true, false)) + facet = node.type.prop(languageDataProp) || facet; + } + return facet; +} /** -Delete the selection or the character after the cursor. +A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer +[LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser) +parsers. */ -const deleteCharForward = view => deleteByChar(view, true); -const deleteByGroup = (target, forward) => deleteBy(target, start => { - let pos = start, { state } = target, line = state.doc.lineAt(pos); - let categorize = state.charCategorizer(pos); - for (let cat = null;;) { - if (pos == (forward ? line.to : line.from)) { - if (pos == start && line.number != (forward ? state.doc.lines : 1)) - pos += forward ? 1 : -1; - break; - } - let next = text.findClusterBreak(line.text, pos - line.from, forward) + line.from; - let nextChar = line.text.slice(Math.min(pos, next) - line.from, Math.max(pos, next) - line.from); - let nextCat = categorize(nextChar); - if (cat != null && nextCat != cat) - break; - if (nextChar != " " || pos != start) - cat = nextCat; - pos = next; +class LRLanguage extends Language { + constructor(data, parser) { + super(data, parser, parser.topNode); + this.parser = parser; } - return skipAtomic(target, pos, forward); -}); + /** + Define a language from a parser. + */ + static define(spec) { + let data = defineLanguageFacet(spec.languageData); + return new LRLanguage(data, spec.parser.configure({ + props: [languageDataProp.add(type => type.isTop ? data : undefined)] + })); + } + /** + Create a new instance of this language with a reconfigured + version of its parser. + */ + configure(options) { + return new LRLanguage(this.data, this.parser.configure(options)); + } + get allowsNesting() { return this.parser.wrappers.length > 0; } // FIXME +} /** -Delete the selection or backward until the end of the next -[group](https://codemirror.net/6/docs/ref/#view.EditorView.moveByGroup), only skipping groups of -whitespace when they consist of a single space. +Get the syntax tree for a state, which is the current (possibly +incomplete) parse tree of active [language](https://codemirror.net/6/docs/ref/#language.Language), +or the empty tree if there is no language available. */ -const deleteGroupBackward = target => deleteByGroup(target, false); +function syntaxTree(state) { + let field = state.field(Language.state, false); + return field ? field.tree : common.Tree.empty; +} /** -Delete the selection or forward until the end of the next group. +Try to get a parse tree that spans at least up to `upto`. The +method will do at most `timeout` milliseconds of work to parse +up to that point if the tree isn't already available. */ -const deleteGroupForward = target => deleteByGroup(target, true); +function ensureSyntaxTree(state, upto, timeout = 50) { + var _a; + let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context; + return !parse ? null : parse.isDone(upto) || parse.work(timeout, upto) ? parse.tree : null; +} /** -Delete the selection, or, if it is a cursor selection, delete to -the end of the line. If the cursor is directly at the end of the -line, delete the line break after it. +Queries whether there is a full syntax tree available up to the +given document position. If there isn't, the background parse +process _might_ still be working and update the tree further, but +there is no guarantee of that—the parser will [stop +working](https://codemirror.net/6/docs/ref/#language.syntaxParserStopped) when it has spent a +certain amount of time or has moved beyond the visible viewport. +Always returns false if no language has been enabled. */ -const deleteToLineEnd = view => deleteBy(view, pos => { - let lineEnd = view.lineBlockAt(pos).to; - return skipAtomic(view, pos < lineEnd ? lineEnd : Math.min(view.state.doc.length, pos + 1), true); -}); +function syntaxTreeAvailable(state, upto = state.doc.length) { + var _a; + return ((_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context.isDone(upto)) || false; +} /** -Delete the selection, or, if it is a cursor selection, delete to -the start of the line. If the cursor is directly at the start of the -line, delete the line break before it. +Tells you whether the language parser is planning to do more +parsing work (in a `requestIdleCallback` pseudo-thread) or has +stopped running, either because it parsed the entire document, +because it spent too much time and was cut off, or because there +is no language parser enabled. */ -const deleteToLineStart = view => deleteBy(view, pos => { - let lineStart = view.lineBlockAt(pos).from; - return skipAtomic(view, pos > lineStart ? lineStart : Math.max(0, pos - 1), false); -}); +function syntaxParserRunning(view) { + var _a; + return ((_a = view.plugin(parseWorker)) === null || _a === void 0 ? void 0 : _a.isWorking()) || false; +} +// Lezer-style Input object for a Text document. +class DocInput { + constructor(doc, length = doc.length) { + this.doc = doc; + this.length = length; + this.cursorPos = 0; + this.string = ""; + this.cursor = doc.iter(); + } + syncTo(pos) { + this.string = this.cursor.next(pos - this.cursorPos).value; + this.cursorPos = pos + this.string.length; + return this.cursorPos - this.string.length; + } + chunk(pos) { + this.syncTo(pos); + return this.string; + } + get lineChunks() { return true; } + read(from, to) { + let stringStart = this.cursorPos - this.string.length; + if (from < stringStart || to >= this.cursorPos) + return this.doc.sliceString(from, to); + else + return this.string.slice(from - stringStart, to - stringStart); + } +} +let currentContext = null; /** -Delete all whitespace directly before a line end from the -document. +A parse context provided to parsers working on the editor content. */ -const deleteTrailingWhitespace = ({ state, dispatch }) => { - if (state.readOnly) - return false; - let changes = []; - for (let pos = 0, prev = "", iter = state.doc.iter();;) { - iter.next(); - if (iter.lineBreak || iter.done) { - let trailing = prev.search(/\s+$/); - if (trailing > -1) - changes.push({ from: pos - (prev.length - trailing), to: pos }); - if (iter.done) - break; - prev = ""; +class ParseContext { + /** + @internal + */ + constructor(parser, + /** + The current editor state. + */ + state, + /** + Tree fragments that can be reused by incremental re-parses. + */ + fragments = [], + /** + @internal + */ + tree, treeLen, + /** + The current editor viewport (or some overapproximation + thereof). Intended to be used for opportunistically avoiding + work (in which case + [`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.ParseContext.skipUntilInView) + should be called to make sure the parser is restarted when the + skipped region becomes visible). + */ + viewport, + /** + @internal + */ + skipped, + /** + This is where skipping parsers can register a promise that, + when resolved, will schedule a new parse. It is cleared when + the parse worker picks up the promise. @internal + */ + scheduleOn) { + this.parser = parser; + this.state = state; + this.fragments = fragments; + this.tree = tree; + this.treeLen = treeLen; + this.viewport = viewport; + this.skipped = skipped; + this.scheduleOn = scheduleOn; + this.parse = null; + /** + @internal + */ + this.tempSkipped = []; + } + startParse() { + return this.parser.startParse(new DocInput(this.state.doc), this.fragments); + } + /** + @internal + */ + work(time, upto) { + if (upto != null && upto >= this.state.doc.length) + upto = undefined; + if (this.tree != common.Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) { + this.takeTree(); + return true; } - else { - prev = iter.value; + return this.withContext(() => { + var _a; + let endTime = Date.now() + time; + if (!this.parse) + this.parse = this.startParse(); + if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) && + upto < this.state.doc.length) + this.parse.stopAt(upto); + for (;;) { + let done = this.parse.advance(); + if (done) { + this.fragments = this.withoutTempSkipped(common.TreeFragment.addTree(done, this.fragments, this.parse.stoppedAt != null)); + this.treeLen = (_a = this.parse.stoppedAt) !== null && _a !== void 0 ? _a : this.state.doc.length; + this.tree = done; + this.parse = null; + if (this.treeLen < (upto !== null && upto !== void 0 ? upto : this.state.doc.length)) + this.parse = this.startParse(); + else + return true; + } + if (Date.now() > endTime) + return false; + } + }); + } + /** + @internal + */ + takeTree() { + let pos, tree; + if (this.parse && (pos = this.parse.parsedPos) >= this.treeLen) { + if (this.parse.stoppedAt == null || this.parse.stoppedAt > pos) + this.parse.stopAt(pos); + this.withContext(() => { while (!(tree = this.parse.advance())) { } }); + this.treeLen = pos; + this.tree = tree; + this.fragments = this.withoutTempSkipped(common.TreeFragment.addTree(this.tree, this.fragments, true)); + this.parse = null; } - pos += iter.value.length; } - if (!changes.length) - return false; - dispatch(state.update({ changes, userEvent: "delete" })); - return true; -}; -/** -Replace each selection range with a line break, leaving the cursor -on the line before the break. -*/ -const splitLine = ({ state: state$1, dispatch }) => { - if (state$1.readOnly) - return false; - let changes = state$1.changeByRange(range => { - return { changes: { from: range.from, to: range.to, insert: text.Text.of(["", ""]) }, - range: state.EditorSelection.cursor(range.from) }; - }); - dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: "input" })); - return true; -}; -/** -Flip the characters before and after the cursor(s). -*/ -const transposeChars = ({ state: state$1, dispatch }) => { - if (state$1.readOnly) - return false; - let changes = state$1.changeByRange(range => { - if (!range.empty || range.from == 0 || range.from == state$1.doc.length) - return { range }; - let pos = range.from, line = state$1.doc.lineAt(pos); - let from = pos == line.from ? pos - 1 : text.findClusterBreak(line.text, pos - line.from, false) + line.from; - let to = pos == line.to ? pos + 1 : text.findClusterBreak(line.text, pos - line.from, true) + line.from; - return { changes: { from, to, insert: state$1.doc.slice(pos, to).append(state$1.doc.slice(from, pos)) }, - range: state.EditorSelection.cursor(to) }; - }); - if (changes.changes.empty) - return false; - dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: "move.character" })); - return true; -}; -function selectedLineBlocks(state) { - let blocks = [], upto = -1; - for (let range of state.selection.ranges) { - let startLine = state.doc.lineAt(range.from), endLine = state.doc.lineAt(range.to); - if (!range.empty && range.to == endLine.from) - endLine = state.doc.lineAt(range.to - 1); - if (upto >= startLine.number) { - let prev = blocks[blocks.length - 1]; - prev.to = endLine.to; - prev.ranges.push(range); + withContext(f) { + let prev = currentContext; + currentContext = this; + try { + return f(); } - else { - blocks.push({ from: startLine.from, to: endLine.to, ranges: [range] }); + finally { + currentContext = prev; } - upto = endLine.number + 1; } - return blocks; -} -function moveLine(state$1, dispatch, forward) { - if (state$1.readOnly) - return false; - let changes = [], ranges = []; - for (let block of selectedLineBlocks(state$1)) { - if (forward ? block.to == state$1.doc.length : block.from == 0) - continue; - let nextLine = state$1.doc.lineAt(forward ? block.to + 1 : block.from - 1); - let size = nextLine.length + 1; - if (forward) { - changes.push({ from: block.to, to: nextLine.to }, { from: block.from, insert: nextLine.text + state$1.lineBreak }); - for (let r of block.ranges) - ranges.push(state.EditorSelection.range(Math.min(state$1.doc.length, r.anchor + size), Math.min(state$1.doc.length, r.head + size))); + withoutTempSkipped(fragments) { + for (let r; r = this.tempSkipped.pop();) + fragments = cutFragments(fragments, r.from, r.to); + return fragments; + } + /** + @internal + */ + changes(changes, newState) { + let { fragments, tree, treeLen, viewport, skipped } = this; + this.takeTree(); + if (!changes.empty) { + let ranges = []; + changes.iterChangedRanges((fromA, toA, fromB, toB) => ranges.push({ fromA, toA, fromB, toB })); + fragments = common.TreeFragment.applyChanges(fragments, ranges); + tree = common.Tree.empty; + treeLen = 0; + viewport = { from: changes.mapPos(viewport.from, -1), to: changes.mapPos(viewport.to, 1) }; + if (this.skipped.length) { + skipped = []; + for (let r of this.skipped) { + let from = changes.mapPos(r.from, 1), to = changes.mapPos(r.to, -1); + if (from < to) + skipped.push({ from, to }); + } + } } - else { - changes.push({ from: nextLine.from, to: block.from }, { from: block.to, insert: state$1.lineBreak + nextLine.text }); - for (let r of block.ranges) - ranges.push(state.EditorSelection.range(r.anchor - size, r.head - size)); + return new ParseContext(this.parser, newState, fragments, tree, treeLen, viewport, skipped, this.scheduleOn); + } + /** + @internal + */ + updateViewport(viewport) { + if (this.viewport.from == viewport.from && this.viewport.to == viewport.to) + return false; + this.viewport = viewport; + let startLen = this.skipped.length; + for (let i = 0; i < this.skipped.length; i++) { + let { from, to } = this.skipped[i]; + if (from < viewport.to && to > viewport.from) { + this.fragments = cutFragments(this.fragments, from, to); + this.skipped.splice(i--, 1); + } + } + if (this.skipped.length >= startLen) + return false; + this.reset(); + return true; + } + /** + @internal + */ + reset() { + if (this.parse) { + this.takeTree(); + this.parse = null; } } - if (!changes.length) - return false; - dispatch(state$1.update({ - changes, - scrollIntoView: true, - selection: state.EditorSelection.create(ranges, state$1.selection.mainIndex), - userEvent: "move.line" - })); - return true; + /** + Notify the parse scheduler that the given region was skipped + because it wasn't in view, and the parse should be restarted + when it comes into view. + */ + skipUntilInView(from, to) { + this.skipped.push({ from, to }); + } + /** + Returns a parser intended to be used as placeholder when + asynchronously loading a nested parser. It'll skip its input and + mark it as not-really-parsed, so that the next update will parse + it again. + + When `until` is given, a reparse will be scheduled when that + promise resolves. + */ + static getSkippingParser(until) { + return new class extends common.Parser { + createParse(input, fragments, ranges) { + let from = ranges[0].from, to = ranges[ranges.length - 1].to; + let parser = { + parsedPos: from, + advance() { + let cx = currentContext; + if (cx) { + for (let r of ranges) + cx.tempSkipped.push(r); + if (until) + cx.scheduleOn = cx.scheduleOn ? Promise.all([cx.scheduleOn, until]) : until; + } + this.parsedPos = to; + return new common.Tree(common.NodeType.none, [], [], to - from); + }, + stoppedAt: null, + stopAt() { } + }; + return parser; + } + }; + } + /** + @internal + */ + isDone(upto) { + upto = Math.min(upto, this.state.doc.length); + let frags = this.fragments; + return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto; + } + /** + Get the context for the current parse, or `null` if no editor + parse is in progress. + */ + static get() { return currentContext; } +} +function cutFragments(fragments, from, to) { + return common.TreeFragment.applyChanges(fragments, [{ fromA: from, toA: to, fromB: from, toB: to }]); +} +class LanguageState { + constructor( + // A mutable parse state that is used to preserve work done during + // the lifetime of a state when moving to the next state. + context) { + this.context = context; + this.tree = context.tree; + } + apply(tr) { + if (!tr.docChanged) + return this; + let newCx = this.context.changes(tr.changes, tr.state); + // If the previous parse wasn't done, go forward only up to its + // end position or the end of the viewport, to avoid slowing down + // state updates with parse work beyond the viewport. + let upto = this.context.treeLen == tr.startState.doc.length ? undefined + : Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to); + if (!newCx.work(20 /* Apply */, upto)) + newCx.takeTree(); + return new LanguageState(newCx); + } + static init(state) { + let vpTo = Math.min(3000 /* InitViewport */, state.doc.length); + let parseState = new ParseContext(state.facet(language).parser, state, [], common.Tree.empty, 0, { from: 0, to: vpTo }, [], null); + if (!parseState.work(20 /* Apply */, vpTo)) + parseState.takeTree(); + return new LanguageState(parseState); + } } -/** -Move the selected lines up one line. -*/ -const moveLineUp = ({ state, dispatch }) => moveLine(state, dispatch, false); -/** -Move the selected lines down one line. -*/ -const moveLineDown = ({ state, dispatch }) => moveLine(state, dispatch, true); -function copyLine(state, dispatch, forward) { - if (state.readOnly) - return false; - let changes = []; - for (let block of selectedLineBlocks(state)) { - if (forward) - changes.push({ from: block.from, insert: state.doc.slice(block.from, block.to) + state.lineBreak }); - else - changes.push({ from: block.to, insert: state.lineBreak + state.doc.slice(block.from, block.to) }); +Language.state = state.StateField.define({ + create: LanguageState.init, + update(value, tr) { + for (let e of tr.effects) + if (e.is(Language.setState)) + return e.value; + if (tr.startState.facet(language) != tr.state.facet(language)) + return LanguageState.init(tr.state); + return value.apply(tr); } - dispatch(state.update({ changes, scrollIntoView: true, userEvent: "input.copyline" })); - return true; -} -/** -Create a copy of the selected lines. Keep the selection in the top copy. -*/ -const copyLineUp = ({ state, dispatch }) => copyLine(state, dispatch, false); -/** -Create a copy of the selected lines. Keep the selection in the bottom copy. -*/ -const copyLineDown = ({ state, dispatch }) => copyLine(state, dispatch, true); -/** -Delete selected lines. -*/ -const deleteLine = view => { - if (view.state.readOnly) - return false; - let { state } = view, changes = state.changes(selectedLineBlocks(state).map(({ from, to }) => { - if (from > 0) - from--; - else if (to < state.doc.length) - to++; - return { from, to }; - })); - let selection = updateSel(state.selection, range => view.moveVertically(range, true)).map(changes); - view.dispatch({ changes, selection, scrollIntoView: true, userEvent: "delete.line" }); - return true; -}; -/** -Replace the selection with a newline. -*/ -const insertNewline = ({ state, dispatch }) => { - dispatch(state.update(state.replaceSelection(state.lineBreak), { scrollIntoView: true, userEvent: "input" })); - return true; +}); +let requestIdle = (callback) => { + let timeout = setTimeout(() => callback(), 500 /* MaxPause */); + return () => clearTimeout(timeout); }; -function isBetweenBrackets(state, pos) { - if (/\(\)|\[\]|\{\}/.test(state.sliceDoc(pos - 1, pos + 1))) - return { from: pos, to: pos }; - let context = language.syntaxTree(state).resolveInner(pos); - let before = context.childBefore(pos), after = context.childAfter(pos), closedBy; - if (before && after && before.to <= pos && after.from >= pos && - (closedBy = before.type.prop(common.NodeProp.closedBy)) && closedBy.indexOf(after.name) > -1 && - state.doc.lineAt(before.to).from == state.doc.lineAt(after.from).from) - return { from: before.to, to: after.from }; - return null; -} -/** -Replace the selection with a newline and indent the newly created -line(s). If the current line consists only of whitespace, this -will also delete that whitespace. When the cursor is between -matching brackets, an additional newline will be inserted after -the cursor. -*/ -const insertNewlineAndIndent = newlineAndIndent(false); -/** -Create a blank, indented line below the current line. -*/ -const insertBlankLine = newlineAndIndent(true); -function newlineAndIndent(atEof) { - return ({ state: state$1, dispatch }) => { - if (state$1.readOnly) - return false; - let changes = state$1.changeByRange(range => { - let { from, to } = range, line = state$1.doc.lineAt(from); - let explode = !atEof && from == to && isBetweenBrackets(state$1, from); - if (atEof) - from = to = (to <= line.to ? line : state$1.doc.lineAt(to)).to; - let cx = new language.IndentContext(state$1, { simulateBreak: from, simulateDoubleBreak: !!explode }); - let indent = language.getIndentation(cx, from); - if (indent == null) - indent = /^\s*/.exec(state$1.doc.lineAt(from).text)[0].length; - while (to < line.to && /\s/.test(line.text[to - line.from])) - to++; - if (explode) - ({ from, to } = explode); - else if (from > line.from && from < line.from + 100 && !/\S/.test(line.text.slice(0, from))) - from = line.from; - let insert = ["", language.indentString(state$1, indent)]; - if (explode) - insert.push(language.indentString(state$1, cx.lineIndent(line.from, -1))); - return { changes: { from, to, insert: text.Text.of(insert) }, - range: state.EditorSelection.cursor(from + 1 + insert[1].length) }; - }); - dispatch(state$1.update(changes, { scrollIntoView: true, userEvent: "input" })); - return true; +if (typeof requestIdleCallback != "undefined") + requestIdle = (callback) => { + let idle = -1, timeout = setTimeout(() => { + idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ }); + }, 100 /* MinPause */); + return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle); }; -} -function changeBySelectedLine(state$1, f) { - let atLine = -1; - return state$1.changeByRange(range => { - let changes = []; - for (let pos = range.from; pos <= range.to;) { - let line = state$1.doc.lineAt(pos); - if (line.number > atLine && (range.empty || range.to > line.from)) { - f(line, changes, range); - atLine = line.number; - } - pos = line.to + 1; +const parseWorker = view.ViewPlugin.fromClass(class ParseWorker { + constructor(view) { + this.view = view; + this.working = null; + this.workScheduled = 0; + // End of the current time chunk + this.chunkEnd = -1; + // Milliseconds of budget left for this chunk + this.chunkBudget = -1; + this.work = this.work.bind(this); + this.scheduleWork(); + } + update(update) { + let cx = this.view.state.field(Language.state).context; + if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen) + this.scheduleWork(); + if (update.docChanged) { + if (this.view.hasFocus) + this.chunkBudget += 50 /* ChangeBonus */; + this.scheduleWork(); } - let changeSet = state$1.changes(changes); - return { changes, - range: state.EditorSelection.range(changeSet.mapPos(range.anchor, 1), changeSet.mapPos(range.head, 1)) }; - }); -} -/** -Auto-indent the selected lines. This uses the [indentation service -facet](https://codemirror.net/6/docs/ref/#language.indentService) as source for auto-indent -information. -*/ -const indentSelection = ({ state, dispatch }) => { - if (state.readOnly) - return false; - let updated = Object.create(null); - let context = new language.IndentContext(state, { overrideIndentation: start => { - let found = updated[start]; - return found == null ? -1 : found; - } }); - let changes = changeBySelectedLine(state, (line, changes, range) => { - let indent = language.getIndentation(context, line.from); - if (indent == null) + this.checkAsyncSchedule(cx); + } + scheduleWork() { + if (this.working) return; - if (!/\S/.test(line.text)) - indent = 0; - let cur = /^\s*/.exec(line.text)[0]; - let norm = language.indentString(state, indent); - if (cur != norm || range.from < line.from + cur.length) { - updated[line.from] = indent; - changes.push({ from: line.from, to: line.from + cur.length, insert: norm }); + let { state } = this.view, field = state.field(Language.state); + if (field.tree != field.context.tree || !field.context.isDone(state.doc.length)) + this.working = requestIdle(this.work); + } + work(deadline) { + this.working = null; + let now = Date.now(); + if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk + this.chunkEnd = now + 30000 /* ChunkTime */; + this.chunkBudget = 3000 /* ChunkBudget */; } - }); - if (!changes.changes.empty) - dispatch(state.update(changes, { userEvent: "indent" })); - return true; -}; -/** -Add a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation to all selected -lines. -*/ -const indentMore = ({ state, dispatch }) => { - if (state.readOnly) - return false; - dispatch(state.update(changeBySelectedLine(state, (line, changes) => { - changes.push({ from: line.from, insert: state.facet(language.indentUnit) }); - }), { userEvent: "input.indent" })); - return true; -}; -/** -Remove a [unit](https://codemirror.net/6/docs/ref/#language.indentUnit) of indentation from all -selected lines. -*/ -const indentLess = ({ state, dispatch }) => { - if (state.readOnly) - return false; - dispatch(state.update(changeBySelectedLine(state, (line, changes) => { - let space = /^\s*/.exec(line.text)[0]; - if (!space) + if (this.chunkBudget <= 0) + return; // No more budget + let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state); + if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */)) return; - let col = text.countColumn(space, state.tabSize), keep = 0; - let insert = language.indentString(state, Math.max(0, col - language.getIndentUnit(state))); - while (keep < space.length && keep < insert.length && space.charCodeAt(keep) == insert.charCodeAt(keep)) - keep++; - changes.push({ from: line.from + keep, to: line.from + space.length, insert: insert.slice(keep) }); - }), { userEvent: "delete.dedent" })); - return true; -}; -/** -Insert a tab character at the cursor or, if something is selected, -use [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) to indent the entire -selection. -*/ -const insertTab = ({ state, dispatch }) => { - if (state.selection.ranges.some(r => !r.empty)) - return indentMore({ state, dispatch }); - dispatch(state.update(state.replaceSelection("\t"), { scrollIntoView: true, userEvent: "input" })); - return true; -}; -/** -Array of key bindings containing the Emacs-style bindings that are -available on macOS by default. - - - Ctrl-b: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift) - - Ctrl-f: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift) - - Ctrl-p: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift) - - Ctrl-n: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift) - - Ctrl-a: [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift) - - Ctrl-e: [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift) - - Ctrl-d: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward) - - Ctrl-h: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward) - - Ctrl-k: [`deleteToLineEnd`](https://codemirror.net/6/docs/ref/#commands.deleteToLineEnd) - - Ctrl-Alt-h: [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward) - - Ctrl-o: [`splitLine`](https://codemirror.net/6/docs/ref/#commands.splitLine) - - Ctrl-t: [`transposeChars`](https://codemirror.net/6/docs/ref/#commands.transposeChars) - - Ctrl-v: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) - - Alt-v: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) -*/ -const emacsStyleKeymap = [ - { key: "Ctrl-b", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, - { key: "Ctrl-f", run: cursorCharRight, shift: selectCharRight }, - { key: "Ctrl-p", run: cursorLineUp, shift: selectLineUp }, - { key: "Ctrl-n", run: cursorLineDown, shift: selectLineDown }, - { key: "Ctrl-a", run: cursorLineStart, shift: selectLineStart }, - { key: "Ctrl-e", run: cursorLineEnd, shift: selectLineEnd }, - { key: "Ctrl-d", run: deleteCharForward }, - { key: "Ctrl-h", run: deleteCharBackward }, - { key: "Ctrl-k", run: deleteToLineEnd }, - { key: "Ctrl-Alt-h", run: deleteGroupBackward }, - { key: "Ctrl-o", run: splitLine }, - { key: "Ctrl-t", run: transposeChars }, - { key: "Ctrl-v", run: cursorPageDown }, -]; -/** -An array of key bindings closely sticking to platform-standard or -widely used bindings. (This includes the bindings from -[`emacsStyleKeymap`](https://codemirror.net/6/docs/ref/#commands.emacsStyleKeymap), with their `key` -property changed to `mac`.) - - - ArrowLeft: [`cursorCharLeft`](https://codemirror.net/6/docs/ref/#commands.cursorCharLeft) ([`selectCharLeft`](https://codemirror.net/6/docs/ref/#commands.selectCharLeft) with Shift) - - ArrowRight: [`cursorCharRight`](https://codemirror.net/6/docs/ref/#commands.cursorCharRight) ([`selectCharRight`](https://codemirror.net/6/docs/ref/#commands.selectCharRight) with Shift) - - Ctrl-ArrowLeft (Alt-ArrowLeft on macOS): [`cursorGroupLeft`](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) ([`selectGroupLeft`](https://codemirror.net/6/docs/ref/#commands.selectGroupLeft) with Shift) - - Ctrl-ArrowRight (Alt-ArrowRight on macOS): [`cursorGroupRight`](https://codemirror.net/6/docs/ref/#commands.cursorGroupRight) ([`selectGroupRight`](https://codemirror.net/6/docs/ref/#commands.selectGroupRight) with Shift) - - Cmd-ArrowLeft (on macOS): [`cursorLineStart`](https://codemirror.net/6/docs/ref/#commands.cursorLineStart) ([`selectLineStart`](https://codemirror.net/6/docs/ref/#commands.selectLineStart) with Shift) - - Cmd-ArrowRight (on macOS): [`cursorLineEnd`](https://codemirror.net/6/docs/ref/#commands.cursorLineEnd) ([`selectLineEnd`](https://codemirror.net/6/docs/ref/#commands.selectLineEnd) with Shift) - - ArrowUp: [`cursorLineUp`](https://codemirror.net/6/docs/ref/#commands.cursorLineUp) ([`selectLineUp`](https://codemirror.net/6/docs/ref/#commands.selectLineUp) with Shift) - - ArrowDown: [`cursorLineDown`](https://codemirror.net/6/docs/ref/#commands.cursorLineDown) ([`selectLineDown`](https://codemirror.net/6/docs/ref/#commands.selectLineDown) with Shift) - - Cmd-ArrowUp (on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift) - - Cmd-ArrowDown (on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift) - - Ctrl-ArrowUp (on macOS): [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift) - - Ctrl-ArrowDown (on macOS): [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift) - - PageUp: [`cursorPageUp`](https://codemirror.net/6/docs/ref/#commands.cursorPageUp) ([`selectPageUp`](https://codemirror.net/6/docs/ref/#commands.selectPageUp) with Shift) - - PageDown: [`cursorPageDown`](https://codemirror.net/6/docs/ref/#commands.cursorPageDown) ([`selectPageDown`](https://codemirror.net/6/docs/ref/#commands.selectPageDown) with Shift) - - Home: [`cursorLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryBackward) ([`selectLineBoundaryBackward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryBackward) with Shift) - - End: [`cursorLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.cursorLineBoundaryForward) ([`selectLineBoundaryForward`](https://codemirror.net/6/docs/ref/#commands.selectLineBoundaryForward) with Shift) - - Ctrl-Home (Cmd-Home on macOS): [`cursorDocStart`](https://codemirror.net/6/docs/ref/#commands.cursorDocStart) ([`selectDocStart`](https://codemirror.net/6/docs/ref/#commands.selectDocStart) with Shift) - - Ctrl-End (Cmd-Home on macOS): [`cursorDocEnd`](https://codemirror.net/6/docs/ref/#commands.cursorDocEnd) ([`selectDocEnd`](https://codemirror.net/6/docs/ref/#commands.selectDocEnd) with Shift) - - Enter: [`insertNewlineAndIndent`](https://codemirror.net/6/docs/ref/#commands.insertNewlineAndIndent) - - Ctrl-a (Cmd-a on macOS): [`selectAll`](https://codemirror.net/6/docs/ref/#commands.selectAll) - - Backspace: [`deleteCharBackward`](https://codemirror.net/6/docs/ref/#commands.deleteCharBackward) - - Delete: [`deleteCharForward`](https://codemirror.net/6/docs/ref/#commands.deleteCharForward) - - Ctrl-Backspace (Alt-Backspace on macOS): [`deleteGroupBackward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupBackward) - - Ctrl-Delete (Alt-Delete on macOS): [`deleteGroupForward`](https://codemirror.net/6/docs/ref/#commands.deleteGroupForward) - - Cmd-Backspace (macOS): [`deleteToLineStart`](https://codemirror.net/6/docs/ref/#commands.deleteToLineStart). - - Cmd-Delete (macOS): [`deleteToLineEnd`](https://codemirror.net/6/docs/ref/#commands.deleteToLineEnd). -*/ -const standardKeymap = [ - { key: "ArrowLeft", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, - { key: "Mod-ArrowLeft", mac: "Alt-ArrowLeft", run: cursorGroupLeft, shift: selectGroupLeft }, - { mac: "Cmd-ArrowLeft", run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward }, - { key: "ArrowRight", run: cursorCharRight, shift: selectCharRight, preventDefault: true }, - { key: "Mod-ArrowRight", mac: "Alt-ArrowRight", run: cursorGroupRight, shift: selectGroupRight }, - { mac: "Cmd-ArrowRight", run: cursorLineBoundaryForward, shift: selectLineBoundaryForward }, - { key: "ArrowUp", run: cursorLineUp, shift: selectLineUp, preventDefault: true }, - { mac: "Cmd-ArrowUp", run: cursorDocStart, shift: selectDocStart }, - { mac: "Ctrl-ArrowUp", run: cursorPageUp, shift: selectPageUp }, - { key: "ArrowDown", run: cursorLineDown, shift: selectLineDown, preventDefault: true }, - { mac: "Cmd-ArrowDown", run: cursorDocEnd, shift: selectDocEnd }, - { mac: "Ctrl-ArrowDown", run: cursorPageDown, shift: selectPageDown }, - { key: "PageUp", run: cursorPageUp, shift: selectPageUp }, - { key: "PageDown", run: cursorPageDown, shift: selectPageDown }, - { key: "Home", run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward }, - { key: "Mod-Home", run: cursorDocStart, shift: selectDocStart }, - { key: "End", run: cursorLineBoundaryForward, shift: selectLineBoundaryForward }, - { key: "Mod-End", run: cursorDocEnd, shift: selectDocEnd }, - { key: "Enter", run: insertNewlineAndIndent }, - { key: "Mod-a", run: selectAll }, - { key: "Backspace", run: deleteCharBackward, shift: deleteCharBackward }, - { key: "Delete", run: deleteCharForward }, - { key: "Mod-Backspace", mac: "Alt-Backspace", run: deleteGroupBackward }, - { key: "Mod-Delete", mac: "Alt-Delete", run: deleteGroupForward }, - { mac: "Mod-Backspace", run: deleteToLineStart }, - { mac: "Mod-Delete", run: deleteToLineEnd } -].concat(emacsStyleKeymap.map(b => ({ mac: b.key, run: b.run, shift: b.shift }))); -/** -The default keymap. Includes all bindings from -[`standardKeymap`](https://codemirror.net/6/docs/ref/#commands.standardKeymap) plus the following: - -- Alt-ArrowLeft (Ctrl-ArrowLeft on macOS): [`cursorSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxLeft) ([`selectSyntaxLeft`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxLeft) with Shift) -- Alt-ArrowRight (Ctrl-ArrowRight on macOS): [`cursorSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.cursorSyntaxRight) ([`selectSyntaxRight`](https://codemirror.net/6/docs/ref/#commands.selectSyntaxRight) with Shift) -- Alt-ArrowUp: [`moveLineUp`](https://codemirror.net/6/docs/ref/#commands.moveLineUp) -- Alt-ArrowDown: [`moveLineDown`](https://codemirror.net/6/docs/ref/#commands.moveLineDown) -- Shift-Alt-ArrowUp: [`copyLineUp`](https://codemirror.net/6/docs/ref/#commands.copyLineUp) -- Shift-Alt-ArrowDown: [`copyLineDown`](https://codemirror.net/6/docs/ref/#commands.copyLineDown) -- Escape: [`simplifySelection`](https://codemirror.net/6/docs/ref/#commands.simplifySelection) -- Ctrl-Enter (Comd-Enter on macOS): [`insertBlankLine`](https://codemirror.net/6/docs/ref/#commands.insertBlankLine) -- Alt-l (Ctrl-l on macOS): [`selectLine`](https://codemirror.net/6/docs/ref/#commands.selectLine) -- Ctrl-i (Cmd-i on macOS): [`selectParentSyntax`](https://codemirror.net/6/docs/ref/#commands.selectParentSyntax) -- Ctrl-[ (Cmd-[ on macOS): [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess) -- Ctrl-] (Cmd-] on macOS): [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) -- Ctrl-Alt-\\ (Cmd-Alt-\\ on macOS): [`indentSelection`](https://codemirror.net/6/docs/ref/#commands.indentSelection) -- Shift-Ctrl-k (Shift-Cmd-k on macOS): [`deleteLine`](https://codemirror.net/6/docs/ref/#commands.deleteLine) -- Shift-Ctrl-\\ (Shift-Cmd-\\ on macOS): [`cursorMatchingBracket`](https://codemirror.net/6/docs/ref/#commands.cursorMatchingBracket) -*/ -const defaultKeymap = [ - { key: "Alt-ArrowLeft", mac: "Ctrl-ArrowLeft", run: cursorSyntaxLeft, shift: selectSyntaxLeft }, - { key: "Alt-ArrowRight", mac: "Ctrl-ArrowRight", run: cursorSyntaxRight, shift: selectSyntaxRight }, - { key: "Alt-ArrowUp", run: moveLineUp }, - { key: "Shift-Alt-ArrowUp", run: copyLineUp }, - { key: "Alt-ArrowDown", run: moveLineDown }, - { key: "Shift-Alt-ArrowDown", run: copyLineDown }, - { key: "Escape", run: simplifySelection }, - { key: "Mod-Enter", run: insertBlankLine }, - { key: "Alt-l", mac: "Ctrl-l", run: selectLine }, - { key: "Mod-i", run: selectParentSyntax, preventDefault: true }, - { key: "Mod-[", run: indentLess }, - { key: "Mod-]", run: indentMore }, - { key: "Mod-Alt-\\", run: indentSelection }, - { key: "Shift-Mod-k", run: deleteLine }, - { key: "Shift-Mod-\\", run: cursorMatchingBracket } -].concat(standardKeymap); -/** -A binding that binds Tab to [`indentMore`](https://codemirror.net/6/docs/ref/#commands.indentMore) and -Shift-Tab to [`indentLess`](https://codemirror.net/6/docs/ref/#commands.indentLess). -Please see the [Tab example](../../examples/tab/) before using -this. -*/ -const indentWithTab = { key: "Tab", run: indentMore, shift: indentLess }; - -exports.copyLineDown = copyLineDown; -exports.copyLineUp = copyLineUp; -exports.cursorCharBackward = cursorCharBackward; -exports.cursorCharForward = cursorCharForward; -exports.cursorCharLeft = cursorCharLeft; -exports.cursorCharRight = cursorCharRight; -exports.cursorDocEnd = cursorDocEnd; -exports.cursorDocStart = cursorDocStart; -exports.cursorGroupBackward = cursorGroupBackward; -exports.cursorGroupForward = cursorGroupForward; -exports.cursorGroupLeft = cursorGroupLeft; -exports.cursorGroupRight = cursorGroupRight; -exports.cursorLineBoundaryBackward = cursorLineBoundaryBackward; -exports.cursorLineBoundaryForward = cursorLineBoundaryForward; -exports.cursorLineDown = cursorLineDown; -exports.cursorLineEnd = cursorLineEnd; -exports.cursorLineStart = cursorLineStart; -exports.cursorLineUp = cursorLineUp; -exports.cursorMatchingBracket = cursorMatchingBracket; -exports.cursorPageDown = cursorPageDown; -exports.cursorPageUp = cursorPageUp; -exports.cursorSubwordBackward = cursorSubwordBackward; -exports.cursorSubwordForward = cursorSubwordForward; -exports.cursorSyntaxLeft = cursorSyntaxLeft; -exports.cursorSyntaxRight = cursorSyntaxRight; -exports.defaultKeymap = defaultKeymap; -exports.deleteCharBackward = deleteCharBackward; -exports.deleteCharForward = deleteCharForward; -exports.deleteGroupBackward = deleteGroupBackward; -exports.deleteGroupForward = deleteGroupForward; -exports.deleteLine = deleteLine; -exports.deleteToLineEnd = deleteToLineEnd; -exports.deleteToLineStart = deleteToLineStart; -exports.deleteTrailingWhitespace = deleteTrailingWhitespace; -exports.emacsStyleKeymap = emacsStyleKeymap; -exports.indentLess = indentLess; -exports.indentMore = indentMore; -exports.indentSelection = indentSelection; -exports.indentWithTab = indentWithTab; -exports.insertBlankLine = insertBlankLine; -exports.insertNewline = insertNewline; -exports.insertNewlineAndIndent = insertNewlineAndIndent; -exports.insertTab = insertTab; -exports.moveLineDown = moveLineDown; -exports.moveLineUp = moveLineUp; -exports.selectAll = selectAll; -exports.selectCharBackward = selectCharBackward; -exports.selectCharForward = selectCharForward; -exports.selectCharLeft = selectCharLeft; -exports.selectCharRight = selectCharRight; -exports.selectDocEnd = selectDocEnd; -exports.selectDocStart = selectDocStart; -exports.selectGroupBackward = selectGroupBackward; -exports.selectGroupForward = selectGroupForward; -exports.selectGroupLeft = selectGroupLeft; -exports.selectGroupRight = selectGroupRight; -exports.selectLine = selectLine; -exports.selectLineBoundaryBackward = selectLineBoundaryBackward; -exports.selectLineBoundaryForward = selectLineBoundaryForward; -exports.selectLineDown = selectLineDown; -exports.selectLineEnd = selectLineEnd; -exports.selectLineStart = selectLineStart; -exports.selectLineUp = selectLineUp; -exports.selectMatchingBracket = selectMatchingBracket; -exports.selectPageDown = selectPageDown; -exports.selectPageUp = selectPageUp; -exports.selectParentSyntax = selectParentSyntax; -exports.selectSubwordBackward = selectSubwordBackward; -exports.selectSubwordForward = selectSubwordForward; -exports.selectSyntaxLeft = selectSyntaxLeft; -exports.selectSyntaxRight = selectSyntaxRight; -exports.simplifySelection = simplifySelection; -exports.splitLine = splitLine; -exports.standardKeymap = standardKeymap; -exports.transposeChars = transposeChars; - -},{"@codemirror/language":48,"@codemirror/matchbrackets":49,"@codemirror/state":51,"@codemirror/text":52,"@codemirror/view":54,"@lezer/common":55}],46:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var common = require('@lezer/common'); -var styleMod = require('style-mod'); -var view = require('@codemirror/view'); -var state = require('@codemirror/state'); -var language = require('@codemirror/language'); -var rangeset = require('@codemirror/rangeset'); - -let nextTagID = 0; + let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9); + let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000; + let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */)); + this.chunkBudget -= Date.now() - now; + if (done || this.chunkBudget <= 0) { + field.context.takeTree(); + this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) }); + } + if (this.chunkBudget > 0 && !(done && !viewportFirst)) + this.scheduleWork(); + this.checkAsyncSchedule(field.context); + } + checkAsyncSchedule(cx) { + if (cx.scheduleOn) { + this.workScheduled++; + cx.scheduleOn + .then(() => this.scheduleWork()) + .catch(err => view.logException(this.view.state, err)) + .then(() => this.workScheduled--); + cx.scheduleOn = null; + } + } + destroy() { + if (this.working) + this.working(); + } + isWorking() { + return this.working || this.workScheduled > 0; + } +}, { + eventHandlers: { focus() { this.scheduleWork(); } } +}); /** -Highlighting tags are markers that denote a highlighting category. -They are [associated](https://codemirror.net/6/docs/ref/#highlight.styleTags) with parts of a syntax -tree by a language mode, and then mapped to an actual CSS style by -a [highlight style](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle). - -Because syntax tree node types and highlight styles have to be -able to talk the same language, CodeMirror uses a mostly _closed_ -[vocabulary](https://codemirror.net/6/docs/ref/#highlight.tags) of syntax tags (as opposed to -traditional open string-based systems, which make it hard for -highlighting themes to cover all the tokens produced by the -various languages). - -It _is_ possible to [define](https://codemirror.net/6/docs/ref/#highlight.Tag^define) your own -highlighting tags for system-internal use (where you control both -the language package and the highlighter), but such tags will not -be picked up by regular highlighters (though you can derive them -from standard tags to allow highlighters to fall back to those). +The facet used to associate a language with an editor state. */ -class Tag { +const language = state.Facet.define({ + combine(languages) { return languages.length ? languages[0] : null; }, + enables: [Language.state, parseWorker] +}); +/** +This class bundles a [language object](https://codemirror.net/6/docs/ref/#language.Language) with an +optional set of supporting extensions. Language packages are +encouraged to export a function that optionally takes a +configuration object and returns a `LanguageSupport` instance, as +the main way for client code to use the package. +*/ +class LanguageSupport { /** - @internal + Create a support object. */ constructor( /** - The set of tags that match this tag, starting with this one - itself, sorted in order of decreasing specificity. @internal + The language object. */ - set, + language, /** - The base unmodified tag that this one is based on, if it's - modified @internal + An optional set of supporting extensions. When nesting a + language in another language, the outer language is encouraged + to include the supporting extensions for its inner languages + in its own set of support extensions. */ - base, + support = []) { + this.language = language; + this.support = support; + this.extension = [language, support]; + } +} +/** +Language descriptions are used to store metadata about languages +and to dynamically load them. Their main role is finding the +appropriate language for a filename or dynamically loading nested +parsers. +*/ +class LanguageDescription { + constructor( /** - The modifiers applied to this.base @internal + The name of this language. */ - modified) { - this.set = set; - this.base = base; - this.modified = modified; - /** - @internal - */ - this.id = nextTagID++; + name, + /** + Alternative names for the mode (lowercased, includes `this.name`). + */ + alias, + /** + File extensions associated with this language. + */ + extensions, + /** + Optional filename pattern that should be associated with this + language. + */ + filename, loadFunc, + /** + If the language has been loaded, this will hold its value. + */ + support = undefined) { + this.name = name; + this.alias = alias; + this.extensions = extensions; + this.filename = filename; + this.loadFunc = loadFunc; + this.support = support; + this.loading = null; } /** - Define a new tag. If `parent` is given, the tag is treated as a - sub-tag of that parent, and [highlight - styles](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle) that don't mention this tag - will try to fall back to the parent tag (or grandparent tag, - etc). + Start loading the the language. Will return a promise that + resolves to a [`LanguageSupport`](https://codemirror.net/6/docs/ref/#language.LanguageSupport) + object when the language successfully loads. */ - static define(parent) { - if (parent === null || parent === void 0 ? void 0 : parent.base) - throw new Error("Can not derive from a modified tag"); - let tag = new Tag([], null, []); - tag.set.push(tag); - if (parent) - for (let t of parent.set) - tag.set.push(t); - return tag; + load() { + return this.loading || (this.loading = this.loadFunc().then(support => this.support = support, err => { this.loading = null; throw err; })); } /** - Define a tag _modifier_, which is a function that, given a tag, - will return a tag that is a subtag of the original. Applying the - same modifier to a twice tag will return the same value (`m1(t1) - == m1(t1)`) and applying multiple modifiers will, regardless or - order, produce the same tag (`m1(m2(t1)) == m2(m1(t1))`). - - When multiple modifiers are applied to a given base tag, each - smaller set of modifiers is registered as a parent, so that for - example `m1(m2(m3(t1)))` is a subtype of `m1(m2(t1))`, - `m1(m3(t1)`, and so on. + Create a language description. */ - static defineModifier() { - let mod = new Modifier; - return (tag) => { - if (tag.modified.indexOf(mod) > -1) - return tag; - return Modifier.get(tag.base || tag, tag.modified.concat(mod).sort((a, b) => a.id - b.id)); - }; + static of(spec) { + let { load, support } = spec; + if (!load) { + if (!support) + throw new RangeError("Must pass either 'load' or 'support' to LanguageDescription.of"); + load = () => Promise.resolve(support); + } + return new LanguageDescription(spec.name, (spec.alias || []).concat(spec.name).map(s => s.toLowerCase()), spec.extensions || [], spec.filename, load, support); } -} -let nextModifierID = 0; -class Modifier { - constructor() { - this.instances = []; - this.id = nextModifierID++; + /** + Look for a language in the given array of descriptions that + matches the filename. Will first match + [`filename`](https://codemirror.net/6/docs/ref/#language.LanguageDescription.filename) patterns, + and then [extensions](https://codemirror.net/6/docs/ref/#language.LanguageDescription.extensions), + and return the first language that matches. + */ + static matchFilename(descs, filename) { + for (let d of descs) + if (d.filename && d.filename.test(filename)) + return d; + let ext = /\.([^.]+)$/.exec(filename); + if (ext) + for (let d of descs) + if (d.extensions.indexOf(ext[1]) > -1) + return d; + return null; } - static get(base, mods) { - if (!mods.length) - return base; - let exists = mods[0].instances.find(t => t.base == base && sameArray(mods, t.modified)); - if (exists) - return exists; - let set = [], tag = new Tag(set, base, mods); - for (let m of mods) - m.instances.push(tag); - let configs = permute(mods); - for (let parent of base.set) - for (let config of configs) - set.push(Modifier.get(parent, config)); - return tag; + /** + Look for a language whose name or alias matches the the given + name (case-insensitively). If `fuzzy` is true, and no direct + matchs is found, this'll also search for a language whose name + or alias occurs in the string (for names shorter than three + characters, only when surrounded by non-word characters). + */ + static matchLanguageName(descs, name, fuzzy = true) { + name = name.toLowerCase(); + for (let d of descs) + if (d.alias.some(a => a == name)) + return d; + if (fuzzy) + for (let d of descs) + for (let a of d.alias) { + let found = name.indexOf(a); + if (found > -1 && (a.length > 2 || !/\w/.test(name[found - 1]) && !/\w/.test(name[found + a.length]))) + return d; + } + return null; } } -function sameArray(a, b) { - return a.length == b.length && a.every((x, i) => x == b[i]); -} -function permute(array) { - let result = [array]; - for (let i = 0; i < array.length; i++) { - for (let a of permute(array.slice(0, i).concat(array.slice(i + 1)))) - result.push(a); + +/** +Facet that defines a way to provide a function that computes the +appropriate indentation depth at the start of a given line, or +`null` to indicate no appropriate indentation could be determined. +*/ +const indentService = state.Facet.define(); +/** +Facet for overriding the unit by which indentation happens. +Should be a string consisting either entirely of spaces or +entirely of tabs. When not set, this defaults to 2 spaces. +*/ +const indentUnit = state.Facet.define({ + combine: values => { + if (!values.length) + return " "; + if (!/^(?: +|\t+)$/.test(values[0])) + throw new Error("Invalid indent unit: " + JSON.stringify(values[0])); + return values[0]; } +}); +/** +Return the _column width_ of an indent unit in the state. +Determined by the [`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) +facet, and [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) when that +contains tabs. +*/ +function getIndentUnit(state) { + let unit = state.facet(indentUnit); + return unit.charCodeAt(0) == 9 ? state.tabSize * unit.length : unit.length; +} +/** +Create an indentation string that covers columns 0 to `cols`. +Will use tabs for as much of the columns as possible when the +[`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) facet contains +tabs. +*/ +function indentString(state, cols) { + let result = "", ts = state.tabSize; + if (state.facet(indentUnit).charCodeAt(0) == 9) + while (cols >= ts) { + result += "\t"; + cols -= ts; + } + for (let i = 0; i < cols; i++) + result += " "; return result; } /** -This function is used to add a set of tags to a language syntax -via -[`LRParser.configure`](https://lezer.codemirror.net/docs/ref#lr.LRParser.configure). - -The argument object maps node selectors to [highlighting -tags](https://codemirror.net/6/docs/ref/#highlight.Tag) or arrays of tags. - -Node selectors may hold one or more (space-separated) node paths. -Such a path can be a [node -name](https://lezer.codemirror.net/docs/ref#common.NodeType.name), -or multiple node names (or `*` wildcards) separated by slash -characters, as in `"Block/Declaration/VariableName"`. Such a path -matches the final node but only if its direct parent nodes are the -other nodes mentioned. A `*` in such a path matches any parent, -but only a single level—wildcards that match multiple parents -aren't supported, both for efficiency reasons and because Lezer -trees make it rather hard to reason about what they would match.) - -A path can be ended with `/...` to indicate that the tag assigned -to the node should also apply to all child nodes, even if they -match their own style (by default, only the innermost style is -used). - -When a path ends in `!`, as in `Attribute!`, no further matching -happens for the node's child nodes, and the entire node gets the -given style. - -In this notation, node names that contain `/`, `!`, `*`, or `...` -must be quoted as JSON strings. - -For example: - -```javascript -parser.withProps( - styleTags({ - // Style Number and BigNumber nodes - "Number BigNumber": tags.number, - // Style Escape nodes whose parent is String - "String/Escape": tags.escape, - // Style anything inside Attributes nodes - "Attributes!": tags.meta, - // Add a style to all content inside Italic nodes - "Italic/...": tags.emphasis, - // Style InvalidString nodes as both `string` and `invalid` - "InvalidString": [tags.string, tags.invalid], - // Style the node named "/" as punctuation - '"/"': tags.punctuation - }) -) -``` +Get the indentation at the given position. Will first consult any +[indent services](https://codemirror.net/6/docs/ref/#language.indentService) that are registered, +and if none of those return an indentation, this will check the +syntax tree for the [indent node prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp) +and use that if found. Returns a number when an indentation could +be determined, and null otherwise. */ -function styleTags(spec) { - let byName = Object.create(null); - for (let prop in spec) { - let tags = spec[prop]; - if (!Array.isArray(tags)) - tags = [tags]; - for (let part of prop.split(" ")) - if (part) { - let pieces = [], mode = 2 /* Normal */, rest = part; - for (let pos = 0;;) { - if (rest == "..." && pos > 0 && pos + 3 == part.length) { - mode = 1 /* Inherit */; - break; - } - let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest); - if (!m) - throw new RangeError("Invalid path: " + part); - pieces.push(m[0] == "*" ? null : m[0][0] == '"' ? JSON.parse(m[0]) : m[0]); - pos += m[0].length; - if (pos == part.length) - break; - let next = part[pos++]; - if (pos == part.length && next == "!") { - mode = 0 /* Opaque */; - break; - } - if (next != "/") - throw new RangeError("Invalid path: " + part); - rest = part.slice(pos); - } - let last = pieces.length - 1, inner = pieces[last]; - if (!inner) - throw new RangeError("Invalid path: " + part); - let rule = new Rule(tags, mode, last > 0 ? pieces.slice(0, last) : null); - byName[inner] = rule.sort(byName[inner]); - } +function getIndentation(context, pos) { + if (context instanceof state.EditorState) + context = new IndentContext(context); + for (let service of context.state.facet(indentService)) { + let result = service(context, pos); + if (result != null) + return result; } - return ruleNodeProp.add(byName); -} -const ruleNodeProp = new common.NodeProp(); -const highlightStyle = state.Facet.define({ - combine(stylings) { return stylings.length ? HighlightStyle.combinedMatch(stylings) : null; } -}); -const fallbackHighlightStyle = state.Facet.define({ - combine(values) { return values.length ? values[0].match : null; } -}); -function getHighlightStyle(state) { - return state.facet(highlightStyle) || state.facet(fallbackHighlightStyle); + let tree = syntaxTree(context.state); + return tree ? syntaxIndentation(context, tree, pos) : null; } -class Rule { - constructor(tags, mode, context, next) { - this.tags = tags; - this.mode = mode; - this.context = context; - this.next = next; +/** +Indentation contexts are used when calling [indentation +services](https://codemirror.net/6/docs/ref/#language.indentService). They provide helper utilities +useful in indentation logic, and can selectively override the +indentation reported for some lines. +*/ +class IndentContext { + /** + Create an indent context. + */ + constructor( + /** + The editor state. + */ + state, + /** + @internal + */ + options = {}) { + this.state = state; + this.options = options; + this.unit = getIndentUnit(state); } - sort(other) { - if (!other || other.depth < this.depth) { - this.next = other; - return this; + /** + Get a description of the line at the given position, taking + [simulated line + breaks](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) + into account. If there is such a break at `pos`, the `bias` + argument determines whether the part of the line line before or + after the break is used. + */ + lineAt(pos, bias = 1) { + let line = this.state.doc.lineAt(pos); + let { simulateBreak } = this.options; + if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) { + if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos) + return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak }; + else + return { text: line.text.slice(0, simulateBreak - line.from), from: line.from }; } - other.next = this.sort(other.next); - return other; + return line; + } + /** + Get the text directly after `pos`, either the entire line + or the next 100 characters, whichever is shorter. + */ + textAfterPos(pos, bias = 1) { + if (this.options.simulateDoubleBreak && pos == this.options.simulateBreak) + return ""; + let { text, from } = this.lineAt(pos, bias); + return text.slice(pos - from, Math.min(text.length, pos + 100 - from)); + } + /** + Find the column for the given position. + */ + column(pos, bias = 1) { + let { text, from } = this.lineAt(pos, bias); + let result = this.countColumn(text, pos - from); + let override = this.options.overrideIndentation ? this.options.overrideIndentation(from) : -1; + if (override > -1) + result += override - this.countColumn(text, text.search(/\S|$/)); + return result; + } + /** + Find the column position (taking tabs into account) of the given + position in the given string. + */ + countColumn(line, pos = line.length) { + return text.countColumn(line, this.state.tabSize, pos); + } + /** + Find the indentation column of the line at the given point. + */ + lineIndent(pos, bias = 1) { + let { text, from } = this.lineAt(pos, bias); + let override = this.options.overrideIndentation; + if (override) { + let overriden = override(from); + if (overriden > -1) + return overriden; + } + return this.countColumn(text, text.search(/\S|$/)); + } + /** + Returns the [simulated line + break](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) + for this context, if any. + */ + get simulatedBreak() { + return this.options.simulateBreak || null; } - get depth() { return this.context ? this.context.length : 0; } } /** -A highlight style associates CSS styles with higlighting -[tags](https://codemirror.net/6/docs/ref/#highlight.Tag). +A syntax tree node prop used to associate indentation strategies +with node types. Such a strategy is a function from an indentation +context to a column number or null, where null indicates that no +definitive indentation can be determined. */ -class HighlightStyle { - constructor(spec, options) { - this.map = Object.create(null); - let modSpec; - function def(spec) { - let cls = styleMod.StyleModule.newName(); - (modSpec || (modSpec = Object.create(null)))["." + cls] = spec; - return cls; - } - this.all = typeof options.all == "string" ? options.all : options.all ? def(options.all) : null; - for (let style of spec) { - let cls = (style.class || def(Object.assign({}, style, { tag: null }))) + - (this.all ? " " + this.all : ""); - let tags = style.tag; - if (!Array.isArray(tags)) - this.map[tags.id] = cls; - else - for (let tag of tags) - this.map[tag.id] = cls; - } - this.module = modSpec ? new styleMod.StyleModule(modSpec) : null; - this.scope = options.scope || null; - this.match = this.match.bind(this); - let ext = [treeHighlighter]; - if (this.module) - ext.push(view.EditorView.styleModule.of(this.module)); - this.extension = ext.concat(highlightStyle.of(this)); - this.fallback = ext.concat(fallbackHighlightStyle.of(this)); +const indentNodeProp = new common.NodeProp(); +// Compute the indentation for a given position from the syntax tree. +function syntaxIndentation(cx, ast, pos) { + return indentFrom(ast.resolveInner(pos).enterUnfinishedNodesBefore(pos), pos, cx); +} +function ignoreClosed(cx) { + return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak; +} +function indentStrategy(tree) { + let strategy = tree.type.prop(indentNodeProp); + if (strategy) + return strategy; + let first = tree.firstChild, close; + if (first && (close = first.type.prop(common.NodeProp.closedBy))) { + let last = tree.lastChild, closed = last && close.indexOf(last.name) > -1; + return cx => delimitedStrategy(cx, true, 1, undefined, closed && !ignoreClosed(cx) ? last.from : undefined); + } + return tree.parent == null ? topIndent : null; +} +function indentFrom(node, pos, base) { + for (; node; node = node.parent) { + let strategy = indentStrategy(node); + if (strategy) + return strategy(new TreeIndentContext(base, pos, node)); } + return null; +} +function topIndent() { return 0; } +/** +Objects of this type provide context information and helper +methods to indentation functions. +*/ +class TreeIndentContext extends IndentContext { /** - Returns the CSS class associated with the given tag, if any. - This method is bound to the instance by the constructor. + @internal */ - match(tag, scope) { - if (this.scope && scope != this.scope) - return null; - for (let t of tag.set) { - let match = this.map[t.id]; - if (match !== undefined) { - if (t != tag) - this.map[tag.id] = match; - return match; - } - } - return this.map[tag.id] = this.all; + constructor(base, + /** + The position at which indentation is being computed. + */ + pos, + /** + The syntax tree node to which the indentation strategy + applies. + */ + node) { + super(base.state, base.options); + this.base = base; + this.pos = pos; + this.node = node; } /** - Combines an array of highlight styles into a single match - function that returns all of the classes assigned by the styles - for a given tag. + Get the text directly after `this.pos`, either the entire line + or the next 100 characters, whichever is shorter. */ - static combinedMatch(styles) { - if (styles.length == 1) - return styles[0].match; - let cache = styles.some(s => s.scope) ? undefined : Object.create(null); - return (tag, scope) => { - let cached = cache && cache[tag.id]; - if (cached !== undefined) - return cached; - let result = null; - for (let style of styles) { - let value = style.match(tag, scope); - if (value) - result = result ? result + " " + value : value; - } - if (cache) - cache[tag.id] = result; - return result; - }; + get textAfter() { + return this.textAfterPos(this.pos); } /** - Create a highlighter style that associates the given styles to - the given tags. The spec must be objects that hold a style tag - or array of tags in their `tag` property, and either a single - `class` property providing a static CSS class (for highlighters - like [`classHighlightStyle`](https://codemirror.net/6/docs/ref/#highlight.classHighlightStyle) - that rely on external styling), or a - [`style-mod`](https://github.com/marijnh/style-mod#documentation)-style - set of CSS properties (which define the styling for those tags). - - The CSS rules created for a highlighter will be emitted in the - order of the spec's properties. That means that for elements that - have multiple tags associated with them, styles defined further - down in the list will have a higher CSS precedence than styles - defined earlier. + Get the indentation at the reference line for `this.node`, which + is the line on which it starts, unless there is a node that is + _not_ a parent of this node covering the start of that line. If + so, the line at the start of that node is tried, again skipping + on if it is covered by another such node. */ - static define(specs, options) { - return new HighlightStyle(specs, options || {}); + get baseIndent() { + let line = this.state.doc.lineAt(this.node.from); + // Skip line starts that are covered by a sibling (or cousin, etc) + for (;;) { + let atBreak = this.node.resolve(line.from); + while (atBreak.parent && atBreak.parent.from == atBreak.from) + atBreak = atBreak.parent; + if (isParent(atBreak, this.node)) + break; + line = this.state.doc.lineAt(atBreak.from); + } + return this.lineIndent(line.from); } /** - Returns the CSS classes (if any) that the highlight styles - active in the given state would assign to the given a style - [tag](https://codemirror.net/6/docs/ref/#highlight.Tag) and (optional) language - [scope](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle^define^options.scope). + Continue looking for indentations in the node's parent nodes, + and return the result of that. */ - static get(state, tag, scope) { - let style = getHighlightStyle(state); - return style && style(tag, scope || common.NodeType.none); + continue() { + let parent = this.node.parent; + return parent ? indentFrom(parent, this.pos, this.base) : 0; + } +} +function isParent(parent, of) { + for (let cur = of; cur; cur = cur.parent) + if (parent == cur) + return true; + return false; +} +// Check whether a delimited node is aligned (meaning there are +// non-skipped nodes on the same line as the opening delimiter). And +// if so, return the opening token. +function bracketedAligned(context) { + let tree = context.node; + let openToken = tree.childAfter(tree.from), last = tree.lastChild; + if (!openToken) + return null; + let sim = context.options.simulateBreak; + let openLine = context.state.doc.lineAt(openToken.from); + let lineEnd = sim == null || sim <= openLine.from ? openLine.to : Math.min(openLine.to, sim); + for (let pos = openToken.to;;) { + let next = tree.childAfter(pos); + if (!next || next == last) + return null; + if (!next.type.isSkipped) + return next.from < lineEnd ? openToken : null; + pos = next.to; } } /** -Run the tree highlighter over the given tree. +An indentation strategy for delimited (usually bracketed) nodes. +Will, by default, indent one unit more than the parent's base +indent unless the line starts with a closing token. When `align` +is true and there are non-skipped nodes on the node's opening +line, the content of the node will be aligned with the end of the +opening node, like this: + + foo(bar, + baz) */ -function highlightTree(tree, +function delimitedIndent({ closing, align = true, units = 1 }) { + return (context) => delimitedStrategy(context, align, units, closing); +} +function delimitedStrategy(context, align, units, closing, closedAt) { + let after = context.textAfter, space = after.match(/^\s*/)[0].length; + let closed = closing && after.slice(space, space + closing.length) == closing || closedAt == context.pos + space; + let aligned = align ? bracketedAligned(context) : null; + if (aligned) + return closed ? context.column(aligned.from) : context.column(aligned.to); + return context.baseIndent + (closed ? 0 : context.unit * units); +} /** -Get the CSS classes used to style a given [tag](https://codemirror.net/6/docs/ref/#highlight.Tag), -or `null` if it isn't styled. (You'll often want to pass a -highlight style's [`match`](https://codemirror.net/6/docs/ref/#highlight.HighlightStyle.match) -method here.) +An indentation strategy that aligns a node's content to its base +indentation. */ -getStyle, +const flatIndent = (context) => context.baseIndent; /** -Assign styling to a region of the text. Will be called, in order -of position, for any ranges where more than zero classes apply. -`classes` is a space separated string of CSS classes. +Creates an indentation strategy that, by default, indents +continued lines one unit more than the node's base indentation. +You can provide `except` to prevent indentation of lines that +match a pattern (for example `/^else\b/` in `if`/`else` +constructs), and you can change the amount of units used with the +`units` option. */ -putStyle, +function continuedIndent({ except, units = 1 } = {}) { + return (context) => { + let matchExcept = except && except.test(context.textAfter); + return context.baseIndent + (matchExcept ? 0 : units * context.unit); + }; +} +const DontIndentBeyond = 200; /** -The start of the range to highlight. +Enables reindentation on input. When a language defines an +`indentOnInput` field in its [language +data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt), which must hold a regular +expression, the line at the cursor will be reindented whenever new +text is typed and the input from the start of the line up to the +cursor matches that regexp. + +To avoid unneccesary reindents, it is recommended to start the +regexp with `^` (usually followed by `\s*`), and end it with `$`. +For example, `/^\s*\}$/` will reindent when a closing brace is +added at the start of a line. */ -from = 0, +function indentOnInput() { + return state.EditorState.transactionFilter.of(tr => { + if (!tr.docChanged || !tr.isUserEvent("input.type")) + return tr; + let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head); + if (!rules.length) + return tr; + let doc = tr.newDoc, { head } = tr.newSelection.main, line = doc.lineAt(head); + if (head > line.from + DontIndentBeyond) + return tr; + let lineStart = doc.sliceString(line.from, head); + if (!rules.some(r => r.test(lineStart))) + return tr; + let { state } = tr, last = -1, changes = []; + for (let { head } of state.selection.ranges) { + let line = state.doc.lineAt(head); + if (line.from == last) + continue; + last = line.from; + let indent = getIndentation(state, line.from); + if (indent == null) + continue; + let cur = /^\s*/.exec(line.text)[0]; + let norm = indentString(state, indent); + if (cur != norm) + changes.push({ from: line.from, to: line.from + cur.length, insert: norm }); + } + return changes.length ? [tr, { changes, sequential: true }] : tr; + }); +} + /** -The end of the range. +A facet that registers a code folding service. When called with +the extent of a line, such a function should return a foldable +range that starts on that line (but continues beyond it), if one +can be found. */ -to = tree.length) { - highlightTreeRange(tree, from, to, getStyle, putStyle); +const foldService = state.Facet.define(); +/** +This node prop is used to associate folding information with +syntax node types. Given a syntax node, it should check whether +that tree is foldable and return the range that can be collapsed +when it is. +*/ +const foldNodeProp = new common.NodeProp(); +/** +[Fold](https://codemirror.net/6/docs/ref/#language.foldNodeProp) function that folds everything but +the first and the last child of a syntax node. Useful for nodes +that start and end with delimiters. +*/ +function foldInside(node) { + let first = node.firstChild, last = node.lastChild; + return first && first.to < last.from ? { from: first.to, to: last.type.isError ? node.to : last.from } : null; } -class TreeHighlighter { - constructor(view) { - this.markCache = Object.create(null); - this.tree = language.syntaxTree(view.state); - this.decorations = this.buildDeco(view, getHighlightStyle(view.state)); - } - update(update) { - let tree = language.syntaxTree(update.state), style = getHighlightStyle(update.state); - let styleChange = style != update.startState.facet(highlightStyle); - if (tree.length < update.view.viewport.to && !styleChange && tree.type == this.tree.type) { - this.decorations = this.decorations.map(update.changes); - } - else if (tree != this.tree || update.viewportChanged || styleChange) { - this.tree = tree; - this.decorations = this.buildDeco(update.view, style); +function syntaxFolding(state, start, end) { + let tree = syntaxTree(state); + if (tree.length == 0) + return null; + let inner = tree.resolveInner(end); + let found = null; + for (let cur = inner; cur; cur = cur.parent) { + if (cur.to <= end || cur.from > end) + continue; + if (found && cur.from < start) + break; + let prop = cur.type.prop(foldNodeProp); + if (prop) { + let value = prop(cur, state); + if (value && value.from <= end && value.from >= start && value.to > end) + found = value; } } - buildDeco(view$1, match) { - if (!match || !this.tree.length) - return view.Decoration.none; - let builder = new rangeset.RangeSetBuilder(); - for (let { from, to } of view$1.visibleRanges) { - highlightTreeRange(this.tree, from, to, match, (from, to, style) => { - builder.add(from, to, this.markCache[style] || (this.markCache[style] = view.Decoration.mark({ class: style }))); - }); - } - return builder.finish(); + return found; +} +/** +Check whether the given line is foldable. First asks any fold +services registered through +[`foldService`](https://codemirror.net/6/docs/ref/#language.foldService), and if none of them return +a result, tries to query the [fold node +prop](https://codemirror.net/6/docs/ref/#language.foldNodeProp) of syntax nodes that cover the end +of the line. +*/ +function foldable(state, lineStart, lineEnd) { + for (let service of state.facet(foldService)) { + let result = service(state, lineStart, lineEnd); + if (result) + return result; } + return syntaxFolding(state, lineStart, lineEnd); } -// This extension installs a highlighter that highlights based on the -// syntax tree and highlight style. -const treeHighlighter = state.Prec.high(view.ViewPlugin.fromClass(TreeHighlighter, { - decorations: v => v.decorations -})); -const nodeStack = [""]; -class HighlightBuilder { - constructor(at, style, span) { - this.at = at; - this.style = style; - this.span = span; - this.class = ""; + +exports.IndentContext = IndentContext; +exports.LRLanguage = LRLanguage; +exports.Language = Language; +exports.LanguageDescription = LanguageDescription; +exports.LanguageSupport = LanguageSupport; +exports.ParseContext = ParseContext; +exports.TreeIndentContext = TreeIndentContext; +exports.continuedIndent = continuedIndent; +exports.defineLanguageFacet = defineLanguageFacet; +exports.delimitedIndent = delimitedIndent; +exports.ensureSyntaxTree = ensureSyntaxTree; +exports.flatIndent = flatIndent; +exports.foldInside = foldInside; +exports.foldNodeProp = foldNodeProp; +exports.foldService = foldService; +exports.foldable = foldable; +exports.getIndentUnit = getIndentUnit; +exports.getIndentation = getIndentation; +exports.indentNodeProp = indentNodeProp; +exports.indentOnInput = indentOnInput; +exports.indentService = indentService; +exports.indentString = indentString; +exports.indentUnit = indentUnit; +exports.language = language; +exports.languageDataProp = languageDataProp; +exports.syntaxParserRunning = syntaxParserRunning; +exports.syntaxTree = syntaxTree; +exports.syntaxTreeAvailable = syntaxTreeAvailable; + +},{"@codemirror/state":30,"@codemirror/text":31,"@codemirror/view":33,"@lezer/common":34}],28:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var state = require('@codemirror/state'); +var language = require('@codemirror/language'); +var view = require('@codemirror/view'); +var common = require('@lezer/common'); + +const baseTheme = view.EditorView.baseTheme({ + ".cm-matchingBracket": { backgroundColor: "#328c8252" }, + ".cm-nonmatchingBracket": { backgroundColor: "#bb555544" } +}); +const DefaultScanDist = 10000, DefaultBrackets = "()[]{}"; +const bracketMatchingConfig = state.Facet.define({ + combine(configs) { + return state.combineConfig(configs, { + afterCursor: true, + brackets: DefaultBrackets, + maxScanDistance: DefaultScanDist + }); } - startSpan(at, cls) { - if (cls != this.class) { - this.flush(at); - if (at > this.at) - this.at = at; - this.class = cls; +}); +const matchingMark = view.Decoration.mark({ class: "cm-matchingBracket" }), nonmatchingMark = view.Decoration.mark({ class: "cm-nonmatchingBracket" }); +const bracketMatchingState = state.StateField.define({ + create() { return view.Decoration.none; }, + update(deco, tr) { + if (!tr.docChanged && !tr.selection) + return deco; + let decorations = []; + let config = tr.state.facet(bracketMatchingConfig); + for (let range of tr.state.selection.ranges) { + if (!range.empty) + continue; + let match = matchBrackets(tr.state, range.head, -1, config) + || (range.head > 0 && matchBrackets(tr.state, range.head - 1, 1, config)) + || (config.afterCursor && + (matchBrackets(tr.state, range.head, 1, config) || + (range.head < tr.state.doc.length && matchBrackets(tr.state, range.head + 1, -1, config)))); + if (!match) + continue; + let mark = match.matched ? matchingMark : nonmatchingMark; + decorations.push(mark.range(match.start.from, match.start.to)); + if (match.end) + decorations.push(mark.range(match.end.from, match.end.to)); } + return view.Decoration.set(decorations, true); + }, + provide: f => view.EditorView.decorations.from(f) +}); +const bracketMatchingUnique = [ + bracketMatchingState, + baseTheme +]; +/** +Create an extension that enables bracket matching. Whenever the +cursor is next to a bracket, that bracket and the one it matches +are highlighted. Or, when no matching bracket is found, another +highlighting style is used to indicate this. +*/ +function bracketMatching(config = {}) { + return [bracketMatchingConfig.of(config), bracketMatchingUnique]; +} +function matchingNodes(node, dir, brackets) { + let byProp = node.prop(dir < 0 ? common.NodeProp.openedBy : common.NodeProp.closedBy); + if (byProp) + return byProp; + if (node.name.length == 1) { + let index = brackets.indexOf(node.name); + if (index > -1 && index % 2 == (dir < 0 ? 1 : 0)) + return [brackets[index + dir]]; } - flush(to) { - if (to > this.at && this.class) - this.span(this.at, to, this.class); + return null; +} +/** +Find the matching bracket for the token at `pos`, scanning +direction `dir`. Only the `brackets` and `maxScanDistance` +properties are used from `config`, if given. Returns null if no +bracket was found at `pos`, or a match result otherwise. +*/ +function matchBrackets(state, pos, dir, config = {}) { + let maxScanDistance = config.maxScanDistance || DefaultScanDist, brackets = config.brackets || DefaultBrackets; + let tree = language.syntaxTree(state), node = tree.resolveInner(pos, dir); + for (let cur = node; cur; cur = cur.parent) { + let matches = matchingNodes(cur.type, dir, brackets); + if (matches && cur.from < cur.to) + return matchMarkedBrackets(state, pos, dir, cur, matches, brackets); } - highlightRange(cursor, from, to, inheritedClass, depth, scope) { - let { type, from: start, to: end } = cursor; - if (start >= to || end <= from) - return; - nodeStack[depth] = type.name; - if (type.isTop) - scope = type; - let cls = inheritedClass; - let rule = type.prop(ruleNodeProp), opaque = false; - while (rule) { - if (!rule.context || matchContext(rule.context, nodeStack, depth)) { - for (let tag of rule.tags) { - let st = this.style(tag, scope); - if (st) { - if (cls) - cls += " "; - cls += st; - if (rule.mode == 1 /* Inherit */) - inheritedClass += (inheritedClass ? " " : "") + st; - else if (rule.mode == 0 /* Opaque */) - opaque = true; - } + return matchPlainBrackets(state, pos, dir, tree, node.type, maxScanDistance, brackets); +} +function matchMarkedBrackets(_state, _pos, dir, token, matching, brackets) { + let parent = token.parent, firstToken = { from: token.from, to: token.to }; + let depth = 0, cursor = parent === null || parent === void 0 ? void 0 : parent.cursor; + if (cursor && (dir < 0 ? cursor.childBefore(token.from) : cursor.childAfter(token.to))) + do { + if (dir < 0 ? cursor.to <= token.from : cursor.from >= token.to) { + if (depth == 0 && matching.indexOf(cursor.type.name) > -1 && cursor.from < cursor.to) { + return { start: firstToken, end: { from: cursor.from, to: cursor.to }, matched: true }; } - break; - } - rule = rule.next; - } - this.startSpan(cursor.from, cls); - if (opaque) - return; - let mounted = cursor.tree && cursor.tree.prop(common.NodeProp.mounted); - if (mounted && mounted.overlay) { - let inner = cursor.node.enter(mounted.overlay[0].from + start, 1); - let hasChild = cursor.firstChild(); - for (let i = 0, pos = start;; i++) { - let next = i < mounted.overlay.length ? mounted.overlay[i] : null; - let nextPos = next ? next.from + start : end; - let rangeFrom = Math.max(from, pos), rangeTo = Math.min(to, nextPos); - if (rangeFrom < rangeTo && hasChild) { - while (cursor.from < rangeTo) { - this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, depth + 1, scope); - this.startSpan(Math.min(to, cursor.to), cls); - if (cursor.to >= nextPos || !cursor.nextSibling()) - break; - } + else if (matchingNodes(cursor.type, dir, brackets)) { + depth++; } - if (!next || nextPos > to) - break; - pos = next.to + start; - if (pos > from) { - this.highlightRange(inner.cursor, Math.max(from, next.from + start), Math.min(to, pos), inheritedClass, depth, mounted.tree.type); - this.startSpan(pos, cls); + else if (matchingNodes(cursor.type, -dir, brackets)) { + depth--; + if (depth == 0) + return { + start: firstToken, + end: cursor.from == cursor.to ? undefined : { from: cursor.from, to: cursor.to }, + matched: false + }; } } - if (hasChild) - cursor.parent(); - } - else if (cursor.firstChild()) { - do { - if (cursor.to <= from) - continue; - if (cursor.from >= to) - break; - this.highlightRange(cursor, from, to, inheritedClass, depth + 1, scope); - this.startSpan(Math.min(to, cursor.to), cls); - } while (cursor.nextSibling()); - cursor.parent(); - } - } -} -function highlightTreeRange(tree, from, to, style, span) { - let builder = new HighlightBuilder(from, style, span); - builder.highlightRange(tree.cursor(), from, to, "", 0, tree.type); - builder.flush(to); + } while (dir < 0 ? cursor.prevSibling() : cursor.nextSibling()); + return { start: firstToken, matched: false }; } -function matchContext(context, stack, depth) { - if (context.length > depth - 1) - return false; - for (let d = depth - 1, i = context.length - 1; i >= 0; i--, d--) { - let check = context[i]; - if (check && check != stack[d]) - return false; +function matchPlainBrackets(state, pos, dir, tree, tokenType, maxScanDistance, brackets) { + let startCh = dir < 0 ? state.sliceDoc(pos - 1, pos) : state.sliceDoc(pos, pos + 1); + let bracket = brackets.indexOf(startCh); + if (bracket < 0 || (bracket % 2 == 0) != (dir > 0)) + return null; + let startToken = { from: dir < 0 ? pos - 1 : pos, to: dir > 0 ? pos + 1 : pos }; + let iter = state.doc.iterRange(pos, dir > 0 ? state.doc.length : 0), depth = 0; + for (let distance = 0; !(iter.next()).done && distance <= maxScanDistance;) { + let text = iter.value; + if (dir < 0) + distance += text.length; + let basePos = pos + distance * dir; + for (let pos = dir > 0 ? 0 : text.length - 1, end = dir > 0 ? text.length : -1; pos != end; pos += dir) { + let found = brackets.indexOf(text[pos]); + if (found < 0 || tree.resolve(basePos + pos, 1).type != tokenType) + continue; + if ((found % 2 == 0) == (dir > 0)) { + depth++; + } + else if (depth == 1) { // Closing + return { start: startToken, end: { from: basePos + pos, to: basePos + pos + 1 }, matched: (found >> 1) == (bracket >> 1) }; + } + else { + depth--; + } + } + if (dir > 0) + distance += text.length; } - return true; + return iter.done ? { start: startToken, matched: false } : null; } -const t = Tag.define; -const comment = t(), name = t(), typeName = t(name), propertyName = t(name), literal = t(), string = t(literal), number = t(literal), content = t(), heading = t(content), keyword = t(), operator = t(), punctuation = t(), bracket = t(punctuation), meta = t(); -/** -The default set of highlighting [tags](https://codemirror.net/6/docs/ref/#highlight.Tag^define) used -by regular language packages and themes. -This collection is heavily biased towards programming languages, -and necessarily incomplete. A full ontology of syntactic -constructs would fill a stack of books, and be impractical to -write themes for. So try to make do with this set. If all else -fails, [open an -issue](https://github.com/codemirror/codemirror.next) to propose a -new tag, or [define](https://codemirror.net/6/docs/ref/#highlight.Tag^define) a local custom tag for -your use case. +exports.bracketMatching = bracketMatching; +exports.matchBrackets = matchBrackets; -Note that it is not obligatory to always attach the most specific -tag possible to an element—if your grammar can't easily -distinguish a certain type of element (such as a local variable), -it is okay to style it as its more general variant (a variable). +},{"@codemirror/language":27,"@codemirror/state":30,"@codemirror/view":33,"@lezer/common":34}],29:[function(require,module,exports){ +'use strict'; -For tags that extend some parent tag, the documentation links to -the parent. +Object.defineProperty(exports, '__esModule', { value: true }); + +var state = require('@codemirror/state'); + +/** +Each range is associated with a value, which must inherit from +this class. */ -const tags = { - /** - A comment. - */ - comment, - /** - A line [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). - */ - lineComment: t(comment), - /** - A block [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). - */ - blockComment: t(comment), - /** - A documentation [comment](https://codemirror.net/6/docs/ref/#highlight.tags.comment). - */ - docComment: t(comment), - /** - Any kind of identifier. - */ - name, - /** - The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a variable. - */ - variableName: t(name), - /** - A type [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). - */ - typeName: typeName, - /** - A tag name (subtag of [`typeName`](https://codemirror.net/6/docs/ref/#highlight.tags.typeName)). - */ - tagName: t(typeName), - /** - A property or field [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). - */ - propertyName: propertyName, - /** - An attribute name (subtag of [`propertyName`](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName)). - */ - attributeName: t(propertyName), - /** - The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a class. - */ - className: t(name), - /** - A label [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). - */ - labelName: t(name), - /** - A namespace [name](https://codemirror.net/6/docs/ref/#highlight.tags.name). - */ - namespace: t(name), - /** - The [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) of a macro. - */ - macroName: t(name), - /** - A literal value. - */ - literal, - /** - A string [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). - */ - string, - /** - A documentation [string](https://codemirror.net/6/docs/ref/#highlight.tags.string). - */ - docString: t(string), - /** - A character literal (subtag of [string](https://codemirror.net/6/docs/ref/#highlight.tags.string)). - */ - character: t(string), - /** - An attribute value (subtag of [string](https://codemirror.net/6/docs/ref/#highlight.tags.string)). - */ - attributeValue: t(string), - /** - A number [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). - */ - number, - /** - An integer [number](https://codemirror.net/6/docs/ref/#highlight.tags.number) literal. - */ - integer: t(number), - /** - A floating-point [number](https://codemirror.net/6/docs/ref/#highlight.tags.number) literal. - */ - float: t(number), - /** - A boolean [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). - */ - bool: t(literal), - /** - Regular expression [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). - */ - regexp: t(literal), - /** - An escape [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal), for example a - backslash escape in a string. - */ - escape: t(literal), - /** - A color [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). - */ - color: t(literal), - /** - A URL [literal](https://codemirror.net/6/docs/ref/#highlight.tags.literal). - */ - url: t(literal), - /** - A language keyword. - */ - keyword, - /** - The [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) for the self or this - object. - */ - self: t(keyword), - /** - The [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) for null. - */ - null: t(keyword), - /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) denoting some atomic value. - */ - atom: t(keyword), - /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that represents a unit. - */ - unit: t(keyword), - /** - A modifier [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword). - */ - modifier: t(keyword), - /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that acts as an operator. - */ - operatorKeyword: t(keyword), - /** - A control-flow related [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword). - */ - controlKeyword: t(keyword), - /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) that defines something. - */ - definitionKeyword: t(keyword), +class RangeValue { /** - A [keyword](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) related to defining or - interfacing with modules. + Compare this value with another value. The default + implementation compares by identity. */ - moduleKeyword: t(keyword), + eq(other) { return this == other; } /** - An operator. + Create a [range](https://codemirror.net/6/docs/ref/#rangeset.Range) with this value. */ - operator, + range(from, to = from) { return new Range(from, to, this); } +} +RangeValue.prototype.startSide = RangeValue.prototype.endSide = 0; +RangeValue.prototype.point = false; +RangeValue.prototype.mapMode = state.MapMode.TrackDel; +/** +A range associates a value with a range of positions. +*/ +class Range { /** - An [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that defines something. + @internal */ - derefOperator: t(operator), + constructor( /** - Arithmetic-related [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + The range's start position. */ - arithmeticOperator: t(operator), + from, /** - Logical [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + Its end position. */ - logicOperator: t(operator), + to, /** - Bit [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + The value associated with this range. */ - bitwiseOperator: t(operator), + value) { + this.from = from; + this.to = to; + this.value = value; + } +} +function cmpRange(a, b) { + return a.from - b.from || a.value.startSide - b.value.startSide; +} +class Chunk { + constructor(from, to, value, + // Chunks are marked with the largest point that occurs + // in them (or -1 for no points), so that scans that are + // only interested in points (such as the + // heightmap-related logic) can skip range-only chunks. + maxPoint) { + this.from = from; + this.to = to; + this.value = value; + this.maxPoint = maxPoint; + } + get length() { return this.to[this.to.length - 1]; } + // Find the index of the given position and side. Use the ranges' + // `from` pos when `end == false`, `to` when `end == true`. + findIndex(pos, side, end, startAt = 0) { + let arr = end ? this.to : this.from; + for (let lo = startAt, hi = arr.length;;) { + if (lo == hi) + return lo; + let mid = (lo + hi) >> 1; + let diff = arr[mid] - pos || (end ? this.value[mid].endSide : this.value[mid].startSide) - side; + if (mid == lo) + return diff >= 0 ? lo : hi; + if (diff >= 0) + hi = mid; + else + lo = mid + 1; + } + } + between(offset, from, to, f) { + for (let i = this.findIndex(from, -1000000000 /* Far */, true), e = this.findIndex(to, 1000000000 /* Far */, false, i); i < e; i++) + if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false) + return false; + } + map(offset, changes) { + let value = [], from = [], to = [], newPos = -1, maxPoint = -1; + for (let i = 0; i < this.value.length; i++) { + let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo; + if (curFrom == curTo) { + let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode); + if (mapped == null) + continue; + newFrom = newTo = mapped; + if (val.startSide != val.endSide) { + newTo = changes.mapPos(curFrom, val.endSide); + if (newTo < newFrom) + continue; + } + } + else { + newFrom = changes.mapPos(curFrom, val.startSide); + newTo = changes.mapPos(curTo, val.endSide); + if (newFrom > newTo || newFrom == newTo && val.startSide > 0 && val.endSide <= 0) + continue; + } + if ((newTo - newFrom || val.endSide - val.startSide) < 0) + continue; + if (newPos < 0) + newPos = newFrom; + if (val.point) + maxPoint = Math.max(maxPoint, newTo - newFrom); + value.push(val); + from.push(newFrom - newPos); + to.push(newTo - newPos); + } + return { mapped: value.length ? new Chunk(from, to, value, maxPoint) : null, pos: newPos }; + } +} +/** +A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#rangeset.Range) in a +way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#rangeset.RangeSet.map) and +[update](https://codemirror.net/6/docs/ref/#rangeset.RangeSet.update). This is an immutable data +structure. +*/ +class RangeSet { /** - Comparison [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + @internal */ - compareOperator: t(operator), + constructor( /** - [Operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that updates its operand. + @internal */ - updateOperator: t(operator), + chunkPos, /** - [Operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator) that defines something. + @internal */ - definitionOperator: t(operator), + chunk, /** - Type-related [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + @internal */ - typeOperator: t(operator), + nextLayer = RangeSet.empty, /** - Control-flow [operator](https://codemirror.net/6/docs/ref/#highlight.tags.operator). + @internal */ - controlOperator: t(operator), + maxPoint) { + this.chunkPos = chunkPos; + this.chunk = chunk; + this.nextLayer = nextLayer; + this.maxPoint = maxPoint; + } /** - Program or markup punctuation. + @internal */ - punctuation, + get length() { + let last = this.chunk.length - 1; + return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length); + } /** - [Punctuation](https://codemirror.net/6/docs/ref/#highlight.tags.punctuation) that separates - things. + The number of ranges in the set. */ - separator: t(punctuation), + get size() { + if (this.isEmpty) + return 0; + let size = this.nextLayer.size; + for (let chunk of this.chunk) + size += chunk.value.length; + return size; + } /** - Bracket-style [punctuation](https://codemirror.net/6/docs/ref/#highlight.tags.punctuation). + @internal */ - bracket, + chunkEnd(index) { + return this.chunkPos[index] + this.chunk[index].length; + } /** - Angle [brackets](https://codemirror.net/6/docs/ref/#highlight.tags.bracket) (usually `<` and `>` - tokens). + Update the range set, optionally adding new ranges or filtering + out existing ones. + + (The extra type parameter is just there as a kludge to work + around TypeScript variance issues that prevented `RangeSet` + from being a subtype of `RangeSet` when `X` is a subtype of + `Y`.) */ - angleBracket: t(bracket), + update(updateSpec) { + let { add = [], sort = false, filterFrom = 0, filterTo = this.length } = updateSpec; + let filter = updateSpec.filter; + if (add.length == 0 && !filter) + return this; + if (sort) + add.slice().sort(cmpRange); + if (this.isEmpty) + return add.length ? RangeSet.of(add) : this; + let cur = new LayerCursor(this, null, -1).goto(0), i = 0, spill = []; + let builder = new RangeSetBuilder(); + while (cur.value || i < add.length) { + if (i < add.length && (cur.from - add[i].from || cur.startSide - add[i].value.startSide) >= 0) { + let range = add[i++]; + if (!builder.addInner(range.from, range.to, range.value)) + spill.push(range); + } + else if (cur.rangeIndex == 1 && cur.chunkIndex < this.chunk.length && + (i == add.length || this.chunkEnd(cur.chunkIndex) < add[i].from) && + (!filter || filterFrom > this.chunkEnd(cur.chunkIndex) || filterTo < this.chunkPos[cur.chunkIndex]) && + builder.addChunk(this.chunkPos[cur.chunkIndex], this.chunk[cur.chunkIndex])) { + cur.nextChunk(); + } + else { + if (!filter || filterFrom > cur.to || filterTo < cur.from || filter(cur.from, cur.to, cur.value)) { + if (!builder.addInner(cur.from, cur.to, cur.value)) + spill.push(new Range(cur.from, cur.to, cur.value)); + } + cur.next(); + } + } + return builder.finishInner(this.nextLayer.isEmpty && !spill.length ? RangeSet.empty + : this.nextLayer.update({ add: spill, filter, filterFrom, filterTo })); + } /** - Square [brackets](https://codemirror.net/6/docs/ref/#highlight.tags.bracket) (usually `[` and `]` - tokens). + Map this range set through a set of changes, return the new set. */ - squareBracket: t(bracket), + map(changes) { + if (changes.length == 0 || this.isEmpty) + return this; + let chunks = [], chunkPos = [], maxPoint = -1; + for (let i = 0; i < this.chunk.length; i++) { + let start = this.chunkPos[i], chunk = this.chunk[i]; + let touch = changes.touchesRange(start, start + chunk.length); + if (touch === false) { + maxPoint = Math.max(maxPoint, chunk.maxPoint); + chunks.push(chunk); + chunkPos.push(changes.mapPos(start)); + } + else if (touch === true) { + let { mapped, pos } = chunk.map(start, changes); + if (mapped) { + maxPoint = Math.max(maxPoint, mapped.maxPoint); + chunks.push(mapped); + chunkPos.push(pos); + } + } + } + let next = this.nextLayer.map(changes); + return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next, maxPoint); + } /** - Parentheses (usually `(` and `)` tokens). Subtag of - [bracket](https://codemirror.net/6/docs/ref/#highlight.tags.bracket). + Iterate over the ranges that touch the region `from` to `to`, + calling `f` for each. There is no guarantee that the ranges will + be reported in any specific order. When the callback returns + `false`, iteration stops. */ - paren: t(bracket), + between(from, to, f) { + if (this.isEmpty) + return; + for (let i = 0; i < this.chunk.length; i++) { + let start = this.chunkPos[i], chunk = this.chunk[i]; + if (to >= start && from <= start + chunk.length && + chunk.between(start, from - start, to - start, f) === false) + return; + } + this.nextLayer.between(from, to, f); + } /** - Braces (usually `{` and `}` tokens). Subtag of - [bracket](https://codemirror.net/6/docs/ref/#highlight.tags.bracket). + Iterate over the ranges in this set, in order, including all + ranges that end at or after `from`. */ - brace: t(bracket), + iter(from = 0) { + return HeapCursor.from([this]).goto(from); + } /** - Content, for example plain text in XML or markup documents. + @internal */ - content, + get isEmpty() { return this.nextLayer == this; } /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a heading. + Iterate over the ranges in a collection of sets, in order, + starting from `from`. */ - heading, + static iter(sets, from = 0) { + return HeapCursor.from(sets).goto(from); + } /** - A level 1 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + Iterate over two groups of sets, calling methods on `comparator` + to notify it of possible differences. */ - heading1: t(heading), + static compare(oldSets, newSets, /** - A level 2 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + This indicates how the underlying data changed between these + ranges, and is needed to synchronize the iteration. `from` and + `to` are coordinates in the _new_ space, after these changes. */ - heading2: t(heading), + textDiff, comparator, /** - A level 3 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + Can be used to ignore all non-point ranges, and points below + the given size. When -1, all ranges are compared. */ - heading3: t(heading), + minPointSize = -1) { + let a = oldSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); + let b = newSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); + let sharedChunks = findSharedChunks(a, b, textDiff); + let sideA = new SpanCursor(a, sharedChunks, minPointSize); + let sideB = new SpanCursor(b, sharedChunks, minPointSize); + textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator)); + if (textDiff.empty && textDiff.length == 0) + compare(sideA, 0, sideB, 0, 0, comparator); + } /** - A level 4 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + Compare the contents of two groups of range sets, returning true + if they are equivalent in the given range. */ - heading4: t(heading), + static eq(oldSets, newSets, from = 0, to) { + if (to == null) + to = 1000000000 /* Far */; + let a = oldSets.filter(set => !set.isEmpty && newSets.indexOf(set) < 0); + let b = newSets.filter(set => !set.isEmpty && oldSets.indexOf(set) < 0); + if (a.length != b.length) + return false; + if (!a.length) + return true; + let sharedChunks = findSharedChunks(a, b); + let sideA = new SpanCursor(a, sharedChunks, 0).goto(from), sideB = new SpanCursor(b, sharedChunks, 0).goto(from); + for (;;) { + if (sideA.to != sideB.to || + !sameValues(sideA.active, sideB.active) || + sideA.point && (!sideB.point || !sideA.point.eq(sideB.point))) + return false; + if (sideA.to > to) + return true; + sideA.next(); + sideB.next(); + } + } /** - A level 5 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + Iterate over a group of range sets at the same time, notifying + the iterator about the ranges covering every given piece of + content. Returns the open count (see + [`SpanIterator.span`](https://codemirror.net/6/docs/ref/#rangeset.SpanIterator.span)) at the end + of the iteration. */ - heading5: t(heading), + static spans(sets, from, to, iterator, /** - A level 6 [heading](https://codemirror.net/6/docs/ref/#highlight.tags.heading). + When given and greater than -1, only points of at least this + size are taken into account. */ - heading6: t(heading), + minPointSize = -1) { + var _a; + let cursor = new SpanCursor(sets, null, minPointSize, (_a = iterator.filterPoint) === null || _a === void 0 ? void 0 : _a.bind(iterator)).goto(from), pos = from; + let open = cursor.openStart; + for (;;) { + let curTo = Math.min(cursor.to, to); + if (cursor.point) { + iterator.point(pos, curTo, cursor.point, cursor.activeForPoint(cursor.to), open); + open = cursor.openEnd(curTo) + (cursor.to > curTo ? 1 : 0); + } + else if (curTo > pos) { + iterator.span(pos, curTo, cursor.active, open); + open = cursor.openEnd(curTo); + } + if (cursor.to > to) + break; + pos = cursor.to; + cursor.next(); + } + return open; + } /** - A prose separator (such as a horizontal rule). + Create a range set for the given range or array of ranges. By + default, this expects the ranges to be _sorted_ (by start + position and, if two start at the same position, + `value.startSide`). You can pass `true` as second argument to + cause the method to sort them. */ - contentSeparator: t(content), + static of(ranges, sort = false) { + let build = new RangeSetBuilder(); + for (let range of ranges instanceof Range ? [ranges] : sort ? lazySort(ranges) : ranges) + build.add(range.from, range.to, range.value); + return build.finish(); + } +} +/** +The empty set of ranges. +*/ +RangeSet.empty = new RangeSet([], [], null, -1); +function lazySort(ranges) { + if (ranges.length > 1) + for (let prev = ranges[0], i = 1; i < ranges.length; i++) { + let cur = ranges[i]; + if (cmpRange(prev, cur) > 0) + return ranges.slice().sort(cmpRange); + prev = cur; + } + return ranges; +} +RangeSet.empty.nextLayer = RangeSet.empty; +/** +A range set builder is a data structure that helps build up a +[range set](https://codemirror.net/6/docs/ref/#rangeset.RangeSet) directly, without first allocating +an array of [`Range`](https://codemirror.net/6/docs/ref/#rangeset.Range) objects. +*/ +class RangeSetBuilder { /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a list. + Create an empty builder. */ - list: t(content), + constructor() { + this.chunks = []; + this.chunkPos = []; + this.chunkStart = -1; + this.last = null; + this.lastFrom = -1000000000 /* Far */; + this.lastTo = -1000000000 /* Far */; + this.from = []; + this.to = []; + this.value = []; + this.maxPoint = -1; + this.setMaxPoint = -1; + this.nextLayer = null; + } + finishChunk(newArrays) { + this.chunks.push(new Chunk(this.from, this.to, this.value, this.maxPoint)); + this.chunkPos.push(this.chunkStart); + this.chunkStart = -1; + this.setMaxPoint = Math.max(this.setMaxPoint, this.maxPoint); + this.maxPoint = -1; + if (newArrays) { + this.from = []; + this.to = []; + this.value = []; + } + } /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that represents a quote. + Add a range. Ranges should be added in sorted (by `from` and + `value.startSide`) order. */ - quote: t(content), + add(from, to, value) { + if (!this.addInner(from, to, value)) + (this.nextLayer || (this.nextLayer = new RangeSetBuilder)).add(from, to, value); + } /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is emphasized. + @internal */ - emphasis: t(content), + addInner(from, to, value) { + let diff = from - this.lastTo || value.startSide - this.last.endSide; + if (diff <= 0 && (from - this.lastFrom || value.startSide - this.last.startSide) < 0) + throw new Error("Ranges must be added sorted by `from` position and `startSide`"); + if (diff < 0) + return false; + if (this.from.length == 250 /* ChunkSize */) + this.finishChunk(true); + if (this.chunkStart < 0) + this.chunkStart = from; + this.from.push(from - this.chunkStart); + this.to.push(to - this.chunkStart); + this.last = value; + this.lastFrom = from; + this.lastTo = to; + this.value.push(value); + if (value.point) + this.maxPoint = Math.max(this.maxPoint, to - from); + return true; + } /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is styled strong. + @internal */ - strong: t(content), + addChunk(from, chunk) { + if ((from - this.lastTo || chunk.value[0].startSide - this.last.endSide) < 0) + return false; + if (this.from.length) + this.finishChunk(true); + this.setMaxPoint = Math.max(this.setMaxPoint, chunk.maxPoint); + this.chunks.push(chunk); + this.chunkPos.push(from); + let last = chunk.value.length - 1; + this.last = chunk.value[last]; + this.lastFrom = chunk.from[last] + from; + this.lastTo = chunk.to[last] + from; + return true; + } /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is part of a link. + Finish the range set. Returns the new set. The builder can't be + used anymore after this has been called. */ - link: t(content), + finish() { return this.finishInner(RangeSet.empty); } /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that is styled as code or - monospace. + @internal */ - monospace: t(content), + finishInner(next) { + if (this.from.length) + this.finishChunk(false); + if (this.chunks.length == 0) + return next; + let result = new RangeSet(this.chunkPos, this.chunks, this.nextLayer ? this.nextLayer.finishInner(next) : next, this.setMaxPoint); + this.from = null; // Make sure further `add` calls produce errors + return result; + } +} +function findSharedChunks(a, b, textDiff) { + let inA = new Map(); + for (let set of a) + for (let i = 0; i < set.chunk.length; i++) + if (set.chunk[i].maxPoint <= 0) + inA.set(set.chunk[i], set.chunkPos[i]); + let shared = new Set(); + for (let set of b) + for (let i = 0; i < set.chunk.length; i++) { + let known = inA.get(set.chunk[i]); + if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set.chunkPos[i] && + !(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set.chunk[i].length))) + shared.add(set.chunk[i]); + } + return shared; +} +class LayerCursor { + constructor(layer, skip, minPoint, rank = 0) { + this.layer = layer; + this.skip = skip; + this.minPoint = minPoint; + this.rank = rank; + } + get startSide() { return this.value ? this.value.startSide : 0; } + get endSide() { return this.value ? this.value.endSide : 0; } + goto(pos, side = -1000000000 /* Far */) { + this.chunkIndex = this.rangeIndex = 0; + this.gotoInner(pos, side, false); + return this; + } + gotoInner(pos, side, forward) { + while (this.chunkIndex < this.layer.chunk.length) { + let next = this.layer.chunk[this.chunkIndex]; + if (!(this.skip && this.skip.has(next) || + this.layer.chunkEnd(this.chunkIndex) < pos || + next.maxPoint < this.minPoint)) + break; + this.chunkIndex++; + forward = false; + } + if (this.chunkIndex < this.layer.chunk.length) { + let rangeIndex = this.layer.chunk[this.chunkIndex].findIndex(pos - this.layer.chunkPos[this.chunkIndex], side, true); + if (!forward || this.rangeIndex < rangeIndex) + this.setRangeIndex(rangeIndex); + } + this.next(); + } + forward(pos, side) { + if ((this.to - pos || this.endSide - side) < 0) + this.gotoInner(pos, side, true); + } + next() { + for (;;) { + if (this.chunkIndex == this.layer.chunk.length) { + this.from = this.to = 1000000000 /* Far */; + this.value = null; + break; + } + else { + let chunkPos = this.layer.chunkPos[this.chunkIndex], chunk = this.layer.chunk[this.chunkIndex]; + let from = chunkPos + chunk.from[this.rangeIndex]; + this.from = from; + this.to = chunkPos + chunk.to[this.rangeIndex]; + this.value = chunk.value[this.rangeIndex]; + this.setRangeIndex(this.rangeIndex + 1); + if (this.minPoint < 0 || this.value.point && this.to - this.from >= this.minPoint) + break; + } + } + } + setRangeIndex(index) { + if (index == this.layer.chunk[this.chunkIndex].value.length) { + this.chunkIndex++; + if (this.skip) { + while (this.chunkIndex < this.layer.chunk.length && this.skip.has(this.layer.chunk[this.chunkIndex])) + this.chunkIndex++; + } + this.rangeIndex = 0; + } + else { + this.rangeIndex = index; + } + } + nextChunk() { + this.chunkIndex++; + this.rangeIndex = 0; + this.next(); + } + compare(other) { + return this.from - other.from || this.startSide - other.startSide || this.to - other.to || this.endSide - other.endSide; + } +} +class HeapCursor { + constructor(heap) { + this.heap = heap; + } + static from(sets, skip = null, minPoint = -1) { + let heap = []; + for (let i = 0; i < sets.length; i++) { + for (let cur = sets[i]; !cur.isEmpty; cur = cur.nextLayer) { + if (cur.maxPoint >= minPoint) + heap.push(new LayerCursor(cur, skip, minPoint, i)); + } + } + return heap.length == 1 ? heap[0] : new HeapCursor(heap); + } + get startSide() { return this.value ? this.value.startSide : 0; } + goto(pos, side = -1000000000 /* Far */) { + for (let cur of this.heap) + cur.goto(pos, side); + for (let i = this.heap.length >> 1; i >= 0; i--) + heapBubble(this.heap, i); + this.next(); + return this; + } + forward(pos, side) { + for (let cur of this.heap) + cur.forward(pos, side); + for (let i = this.heap.length >> 1; i >= 0; i--) + heapBubble(this.heap, i); + if ((this.to - pos || this.value.endSide - side) < 0) + this.next(); + } + next() { + if (this.heap.length == 0) { + this.from = this.to = 1000000000 /* Far */; + this.value = null; + this.rank = -1; + } + else { + let top = this.heap[0]; + this.from = top.from; + this.to = top.to; + this.value = top.value; + this.rank = top.rank; + if (top.value) + top.next(); + heapBubble(this.heap, 0); + } + } +} +function heapBubble(heap, index) { + for (let cur = heap[index];;) { + let childIndex = (index << 1) + 1; + if (childIndex >= heap.length) + break; + let child = heap[childIndex]; + if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) { + child = heap[childIndex + 1]; + childIndex++; + } + if (cur.compare(child) < 0) + break; + heap[childIndex] = cur; + heap[index] = child; + index = childIndex; + } +} +class SpanCursor { + constructor(sets, skip, minPoint, filterPoint = () => true) { + this.minPoint = minPoint; + this.filterPoint = filterPoint; + this.active = []; + this.activeTo = []; + this.activeRank = []; + this.minActive = -1; + // A currently active point range, if any + this.point = null; + this.pointFrom = 0; + this.pointRank = 0; + this.to = -1000000000 /* Far */; + this.endSide = 0; + this.openStart = -1; + this.cursor = HeapCursor.from(sets, skip, minPoint); + } + goto(pos, side = -1000000000 /* Far */) { + this.cursor.goto(pos, side); + this.active.length = this.activeTo.length = this.activeRank.length = 0; + this.minActive = -1; + this.to = pos; + this.endSide = side; + this.openStart = -1; + this.next(); + return this; + } + forward(pos, side) { + while (this.minActive > -1 && (this.activeTo[this.minActive] - pos || this.active[this.minActive].endSide - side) < 0) + this.removeActive(this.minActive); + this.cursor.forward(pos, side); + } + removeActive(index) { + remove(this.active, index); + remove(this.activeTo, index); + remove(this.activeRank, index); + this.minActive = findMinIndex(this.active, this.activeTo); + } + addActive(trackOpen) { + let i = 0, { value, to, rank } = this.cursor; + while (i < this.activeRank.length && this.activeRank[i] <= rank) + i++; + insert(this.active, i, value); + insert(this.activeTo, i, to); + insert(this.activeRank, i, rank); + if (trackOpen) + insert(trackOpen, i, this.cursor.from); + this.minActive = findMinIndex(this.active, this.activeTo); + } + // After calling this, if `this.point` != null, the next range is a + // point. Otherwise, it's a regular range, covered by `this.active`. + next() { + let from = this.to, wasPoint = this.point; + this.point = null; + let trackOpen = this.openStart < 0 ? [] : null, trackExtra = 0; + for (;;) { + let a = this.minActive; + if (a > -1 && (this.activeTo[a] - this.cursor.from || this.active[a].endSide - this.cursor.startSide) < 0) { + if (this.activeTo[a] > from) { + this.to = this.activeTo[a]; + this.endSide = this.active[a].endSide; + break; + } + this.removeActive(a); + if (trackOpen) + remove(trackOpen, a); + } + else if (!this.cursor.value) { + this.to = this.endSide = 1000000000 /* Far */; + break; + } + else if (this.cursor.from > from) { + this.to = this.cursor.from; + this.endSide = this.cursor.startSide; + break; + } + else { + let nextVal = this.cursor.value; + if (!nextVal.point) { // Opening a range + this.addActive(trackOpen); + this.cursor.next(); + } + else if (wasPoint && this.cursor.to == this.to && this.cursor.from < this.cursor.to) { + // Ignore any non-empty points that end precisely at the end of the prev point + this.cursor.next(); + } + else if (!this.filterPoint(this.cursor.from, this.cursor.to, this.cursor.value, this.cursor.rank)) { + this.cursor.next(); + } + else { // New point + this.point = nextVal; + this.pointFrom = this.cursor.from; + this.pointRank = this.cursor.rank; + this.to = this.cursor.to; + this.endSide = nextVal.endSide; + if (this.cursor.from < from) + trackExtra = 1; + this.cursor.next(); + if (this.to > from) + this.forward(this.to, this.endSide); + break; + } + } + } + if (trackOpen) { + let openStart = 0; + while (openStart < trackOpen.length && trackOpen[openStart] < from) + openStart++; + this.openStart = openStart + trackExtra; + } + } + activeForPoint(to) { + if (!this.active.length) + return this.active; + let active = []; + for (let i = this.active.length - 1; i >= 0; i--) { + if (this.activeRank[i] < this.pointRank) + break; + if (this.activeTo[i] > to || this.activeTo[i] == to && this.active[i].endSide >= this.point.endSide) + active.push(this.active[i]); + } + return active.reverse(); + } + openEnd(to) { + let open = 0; + for (let i = this.activeTo.length - 1; i >= 0 && this.activeTo[i] > to; i--) + open++; + return open; + } +} +function compare(a, startA, b, startB, length, comparator) { + a.goto(startA); + b.goto(startB); + let endB = startB + length; + let pos = startB, dPos = startB - startA; + for (;;) { + let diff = (a.to + dPos) - b.to || a.endSide - b.endSide; + let end = diff < 0 ? a.to + dPos : b.to, clipEnd = Math.min(end, endB); + if (a.point || b.point) { + if (!(a.point && b.point && (a.point == b.point || a.point.eq(b.point)) && + sameValues(a.activeForPoint(a.to + dPos), b.activeForPoint(b.to)))) + comparator.comparePoint(pos, clipEnd, a.point, b.point); + } + else { + if (clipEnd > pos && !sameValues(a.active, b.active)) + comparator.compareRange(pos, clipEnd, a.active, b.active); + } + if (end > endB) + break; + pos = end; + if (diff <= 0) + a.next(); + if (diff >= 0) + b.next(); + } +} +function sameValues(a, b) { + if (a.length != b.length) + return false; + for (let i = 0; i < a.length; i++) + if (a[i] != b[i] && !a[i].eq(b[i])) + return false; + return true; +} +function remove(array, index) { + for (let i = index, e = array.length - 1; i < e; i++) + array[i] = array[i + 1]; + array.pop(); +} +function insert(array, index, value) { + for (let i = array.length - 1; i >= index; i--) + array[i + 1] = array[i]; + array[index] = value; +} +function findMinIndex(value, array) { + let found = -1, foundPos = 1000000000 /* Far */; + for (let i = 0; i < array.length; i++) + if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) { + found = i; + foundPos = array[i]; + } + return found; +} + +exports.Range = Range; +exports.RangeSet = RangeSet; +exports.RangeSetBuilder = RangeSetBuilder; +exports.RangeValue = RangeValue; + +},{"@codemirror/state":30}],30:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var text = require('@codemirror/text'); + +const DefaultSplit = /\r\n?|\n/; +/** +Distinguishes different ways in which positions can be mapped. +*/ +exports.MapMode = void 0; +(function (MapMode) { /** - [Content](https://codemirror.net/6/docs/ref/#highlight.tags.content) that has a strike-through - style. + Map a position to a valid new position, even when its context + was deleted. */ - strikethrough: t(content), + MapMode[MapMode["Simple"] = 0] = "Simple"; /** - Inserted text in a change-tracking format. + Return null if deletion happens across the position. */ - inserted: t(), + MapMode[MapMode["TrackDel"] = 1] = "TrackDel"; /** - Deleted text. + Return null if the character _before_ the position is deleted. */ - deleted: t(), + MapMode[MapMode["TrackBefore"] = 2] = "TrackBefore"; /** - Changed text. + Return null if the character _after_ the position is deleted. */ - changed: t(), + MapMode[MapMode["TrackAfter"] = 3] = "TrackAfter"; +})(exports.MapMode || (exports.MapMode = {})); +/** +A change description is a variant of [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) +that doesn't store the inserted text. As such, it can't be +applied, but is cheaper to store and manipulate. +*/ +class ChangeDesc { + // Sections are encoded as pairs of integers. The first is the + // length in the current document, and the second is -1 for + // unaffected sections, and the length of the replacement content + // otherwise. So an insertion would be (0, n>0), a deletion (n>0, + // 0), and a replacement two positive numbers. /** - An invalid or unsyntactic element. + @internal */ - invalid: t(), + constructor( /** - Metadata or meta-instruction. + @internal */ - meta, + sections) { + this.sections = sections; + } /** - [Metadata](https://codemirror.net/6/docs/ref/#highlight.tags.meta) that applies to the entire - document. + The length of the document before the change. */ - documentMeta: t(meta), + get length() { + let result = 0; + for (let i = 0; i < this.sections.length; i += 2) + result += this.sections[i]; + return result; + } /** - [Metadata](https://codemirror.net/6/docs/ref/#highlight.tags.meta) that annotates or adds - attributes to a given syntactic element. + The length of the document after the change. */ - annotation: t(meta), + get newLength() { + let result = 0; + for (let i = 0; i < this.sections.length; i += 2) { + let ins = this.sections[i + 1]; + result += ins < 0 ? this.sections[i] : ins; + } + return result; + } /** - Processing instruction or preprocessor directive. Subtag of - [meta](https://codemirror.net/6/docs/ref/#highlight.tags.meta). + False when there are actual changes in this set. */ - processingInstruction: t(meta), + get empty() { return this.sections.length == 0 || this.sections.length == 2 && this.sections[1] < 0; } /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates that a - given element is being defined. Expected to be used with the - various [name](https://codemirror.net/6/docs/ref/#highlight.tags.name) tags. + Iterate over the unchanged parts left by these changes. */ - definition: Tag.defineModifier(), + iterGaps(f) { + for (let i = 0, posA = 0, posB = 0; i < this.sections.length;) { + let len = this.sections[i++], ins = this.sections[i++]; + if (ins < 0) { + f(posA, posB, len); + posB += len; + } + else { + posB += ins; + } + posA += len; + } + } /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates that - something is constant. Mostly expected to be used with - [variable names](https://codemirror.net/6/docs/ref/#highlight.tags.variableName). + Iterate over the ranges changed by these changes. (See + [`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a + variant that also provides you with the inserted text.) + + When `individual` is true, adjacent changes (which are kept + separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are + reported separately. */ - constant: Tag.defineModifier(), + iterChangedRanges(f, individual = false) { + iterChanges(this, f, individual); + } /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) used to indicate that - a [variable](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) or [property - name](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName) is being called or defined - as a function. + Get a description of the inverted form of these changes. */ - function: Tag.defineModifier(), + get invertedDesc() { + let sections = []; + for (let i = 0; i < this.sections.length;) { + let len = this.sections[i++], ins = this.sections[i++]; + if (ins < 0) + sections.push(len, ins); + else + sections.push(ins, len); + } + return new ChangeDesc(sections); + } /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that can be applied to - [names](https://codemirror.net/6/docs/ref/#highlight.tags.name) to indicate that they belong to - the language's standard environment. + Compute the combined effect of applying another set of changes + after this one. The length of the document after this set should + match the length before `other`. */ - standard: Tag.defineModifier(), + composeDesc(other) { return this.empty ? other : other.empty ? this : composeSets(this, other); } /** - [Modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that indicates a given - [names](https://codemirror.net/6/docs/ref/#highlight.tags.name) is local to some scope. + Map this description, which should start with the same document + as `other`, over another set of changes, so that it can be + applied after it. When `before` is true, map as if the changes + in `other` happened before the ones in `this`. */ - local: Tag.defineModifier(), + mapDesc(other, before = false) { return other.empty ? this : mapSet(this, other, before); } + mapPos(pos, assoc = -1, mode = exports.MapMode.Simple) { + let posA = 0, posB = 0; + for (let i = 0; i < this.sections.length;) { + let len = this.sections[i++], ins = this.sections[i++], endA = posA + len; + if (ins < 0) { + if (endA > pos) + return posB + (pos - posA); + posB += len; + } + else { + if (mode != exports.MapMode.Simple && endA >= pos && + (mode == exports.MapMode.TrackDel && posA < pos && endA > pos || + mode == exports.MapMode.TrackBefore && posA < pos || + mode == exports.MapMode.TrackAfter && endA > pos)) + return null; + if (endA > pos || endA == pos && assoc < 0 && !len) + return pos == posA || assoc < 0 ? posB : posB + ins; + posB += ins; + } + posA = endA; + } + if (pos > posA) + throw new RangeError(`Position ${pos} is out of range for changeset of length ${posA}`); + return posB; + } /** - A generic variant [modifier](https://codemirror.net/6/docs/ref/#highlight.Tag^defineModifier) that - can be used to tag language-specific alternative variants of - some common tag. It is recommended for themes to define special - forms of at least the [string](https://codemirror.net/6/docs/ref/#highlight.tags.string) and - [variable name](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) tags, since those - come up a lot. - */ - special: Tag.defineModifier() -}; -/** -A default highlight style (works well with light themes). -*/ -const defaultHighlightStyle = HighlightStyle.define([ - { tag: tags.link, - textDecoration: "underline" }, - { tag: tags.heading, - textDecoration: "underline", - fontWeight: "bold" }, - { tag: tags.emphasis, - fontStyle: "italic" }, - { tag: tags.strong, - fontWeight: "bold" }, - { tag: tags.strikethrough, - textDecoration: "line-through" }, - { tag: tags.keyword, - color: "#708" }, - { tag: [tags.atom, tags.bool, tags.url, tags.contentSeparator, tags.labelName], - color: "#219" }, - { tag: [tags.literal, tags.inserted], - color: "#164" }, - { tag: [tags.string, tags.deleted], - color: "#a11" }, - { tag: [tags.regexp, tags.escape, tags.special(tags.string)], - color: "#e40" }, - { tag: tags.definition(tags.variableName), - color: "#00f" }, - { tag: tags.local(tags.variableName), - color: "#30a" }, - { tag: [tags.typeName, tags.namespace], - color: "#085" }, - { tag: tags.className, - color: "#167" }, - { tag: [tags.special(tags.variableName), tags.macroName], - color: "#256" }, - { tag: tags.definition(tags.propertyName), - color: "#00c" }, - { tag: tags.comment, - color: "#940" }, - { tag: tags.meta, - color: "#7a757a" }, - { tag: tags.invalid, - color: "#f00" } -]); -/** -This is a highlight style that adds stable, predictable classes to -tokens, for styling with external CSS. - -These tags are mapped to their name prefixed with `"cmt-"` (for -example `"cmt-comment"`): - -* [`link`](https://codemirror.net/6/docs/ref/#highlight.tags.link) -* [`heading`](https://codemirror.net/6/docs/ref/#highlight.tags.heading) -* [`emphasis`](https://codemirror.net/6/docs/ref/#highlight.tags.emphasis) -* [`strong`](https://codemirror.net/6/docs/ref/#highlight.tags.strong) -* [`keyword`](https://codemirror.net/6/docs/ref/#highlight.tags.keyword) -* [`atom`](https://codemirror.net/6/docs/ref/#highlight.tags.atom) [`bool`](https://codemirror.net/6/docs/ref/#highlight.tags.bool) -* [`url`](https://codemirror.net/6/docs/ref/#highlight.tags.url) -* [`labelName`](https://codemirror.net/6/docs/ref/#highlight.tags.labelName) -* [`inserted`](https://codemirror.net/6/docs/ref/#highlight.tags.inserted) -* [`deleted`](https://codemirror.net/6/docs/ref/#highlight.tags.deleted) -* [`literal`](https://codemirror.net/6/docs/ref/#highlight.tags.literal) -* [`string`](https://codemirror.net/6/docs/ref/#highlight.tags.string) -* [`number`](https://codemirror.net/6/docs/ref/#highlight.tags.number) -* [`variableName`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) -* [`typeName`](https://codemirror.net/6/docs/ref/#highlight.tags.typeName) -* [`namespace`](https://codemirror.net/6/docs/ref/#highlight.tags.namespace) -* [`className`](https://codemirror.net/6/docs/ref/#highlight.tags.className) -* [`macroName`](https://codemirror.net/6/docs/ref/#highlight.tags.macroName) -* [`propertyName`](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName) -* [`operator`](https://codemirror.net/6/docs/ref/#highlight.tags.operator) -* [`comment`](https://codemirror.net/6/docs/ref/#highlight.tags.comment) -* [`meta`](https://codemirror.net/6/docs/ref/#highlight.tags.meta) -* [`punctuation`](https://codemirror.net/6/docs/ref/#highlight.tags.puncutation) -* [`invalid`](https://codemirror.net/6/docs/ref/#highlight.tags.invalid) - -In addition, these mappings are provided: - -* [`regexp`](https://codemirror.net/6/docs/ref/#highlight.tags.regexp), - [`escape`](https://codemirror.net/6/docs/ref/#highlight.tags.escape), and - [`special`](https://codemirror.net/6/docs/ref/#highlight.tags.special)[`(string)`](https://codemirror.net/6/docs/ref/#highlight.tags.string) - are mapped to `"cmt-string2"` -* [`special`](https://codemirror.net/6/docs/ref/#highlight.tags.special)[`(variableName)`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) - to `"cmt-variableName2"` -* [`local`](https://codemirror.net/6/docs/ref/#highlight.tags.local)[`(variableName)`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) - to `"cmt-variableName cmt-local"` -* [`definition`](https://codemirror.net/6/docs/ref/#highlight.tags.definition)[`(variableName)`](https://codemirror.net/6/docs/ref/#highlight.tags.variableName) - to `"cmt-variableName cmt-definition"` -* [`definition`](https://codemirror.net/6/docs/ref/#highlight.tags.definition)[`(propertyName)`](https://codemirror.net/6/docs/ref/#highlight.tags.propertyName) - to `"cmt-propertyName cmt-definition"` -*/ -const classHighlightStyle = HighlightStyle.define([ - { tag: tags.link, class: "cmt-link" }, - { tag: tags.heading, class: "cmt-heading" }, - { tag: tags.emphasis, class: "cmt-emphasis" }, - { tag: tags.strong, class: "cmt-strong" }, - { tag: tags.keyword, class: "cmt-keyword" }, - { tag: tags.atom, class: "cmt-atom" }, - { tag: tags.bool, class: "cmt-bool" }, - { tag: tags.url, class: "cmt-url" }, - { tag: tags.labelName, class: "cmt-labelName" }, - { tag: tags.inserted, class: "cmt-inserted" }, - { tag: tags.deleted, class: "cmt-deleted" }, - { tag: tags.literal, class: "cmt-literal" }, - { tag: tags.string, class: "cmt-string" }, - { tag: tags.number, class: "cmt-number" }, - { tag: [tags.regexp, tags.escape, tags.special(tags.string)], class: "cmt-string2" }, - { tag: tags.variableName, class: "cmt-variableName" }, - { tag: tags.local(tags.variableName), class: "cmt-variableName cmt-local" }, - { tag: tags.definition(tags.variableName), class: "cmt-variableName cmt-definition" }, - { tag: tags.special(tags.variableName), class: "cmt-variableName2" }, - { tag: tags.definition(tags.propertyName), class: "cmt-propertyName cmt-definition" }, - { tag: tags.typeName, class: "cmt-typeName" }, - { tag: tags.namespace, class: "cmt-namespace" }, - { tag: tags.className, class: "cmt-className" }, - { tag: tags.macroName, class: "cmt-macroName" }, - { tag: tags.propertyName, class: "cmt-propertyName" }, - { tag: tags.operator, class: "cmt-operator" }, - { tag: tags.comment, class: "cmt-comment" }, - { tag: tags.meta, class: "cmt-meta" }, - { tag: tags.invalid, class: "cmt-invalid" }, - { tag: tags.punctuation, class: "cmt-punctuation" } -]); - -exports.HighlightStyle = HighlightStyle; -exports.Tag = Tag; -exports.classHighlightStyle = classHighlightStyle; -exports.defaultHighlightStyle = defaultHighlightStyle; -exports.highlightTree = highlightTree; -exports.styleTags = styleTags; -exports.tags = tags; - -},{"@codemirror/language":48,"@codemirror/rangeset":50,"@codemirror/state":51,"@codemirror/view":54,"@lezer/common":55,"style-mod":120}],47:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var javascript$1 = require('@lezer/javascript'); -var language = require('@codemirror/language'); -var highlight = require('@codemirror/highlight'); -var autocomplete = require('@codemirror/autocomplete'); - -/** -A collection of JavaScript-related -[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet). -*/ -const snippets = [ - autocomplete.snippetCompletion("function ${name}(${params}) {\n\t${}\n}", { - label: "function", - detail: "definition", - type: "keyword" - }), - autocomplete.snippetCompletion("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n\t${}\n}", { - label: "for", - detail: "loop", - type: "keyword" - }), - autocomplete.snippetCompletion("for (let ${name} of ${collection}) {\n\t${}\n}", { - label: "for", - detail: "of loop", - type: "keyword" - }), - autocomplete.snippetCompletion("try {\n\t${}\n} catch (${error}) {\n\t${}\n}", { - label: "try", - detail: "block", - type: "keyword" - }), - autocomplete.snippetCompletion("class ${name} {\n\tconstructor(${params}) {\n\t\t${}\n\t}\n}", { - label: "class", - detail: "definition", - type: "keyword" - }), - autocomplete.snippetCompletion("import {${names}} from \"${module}\"\n${}", { - label: "import", - detail: "named", - type: "keyword" - }), - autocomplete.snippetCompletion("import ${name} from \"${module}\"\n${}", { - label: "import", - detail: "default", - type: "keyword" - }) -]; - -/** -A language provider based on the [Lezer JavaScript -parser](https://github.com/lezer-parser/javascript), extended with -highlighting and indentation information. -*/ -const javascriptLanguage = language.LRLanguage.define({ - parser: javascript$1.parser.configure({ - props: [ - language.indentNodeProp.add({ - IfStatement: language.continuedIndent({ except: /^\s*({|else\b)/ }), - TryStatement: language.continuedIndent({ except: /^\s*({|catch\b|finally\b)/ }), - LabeledStatement: language.flatIndent, - SwitchBody: context => { - let after = context.textAfter, closed = /^\s*\}/.test(after), isCase = /^\s*(case|default)\b/.test(after); - return context.baseIndent + (closed ? 0 : isCase ? 1 : 2) * context.unit; - }, - Block: language.delimitedIndent({ closing: "}" }), - ArrowFunction: cx => cx.baseIndent + cx.unit, - "TemplateString BlockComment": () => -1, - "Statement Property": language.continuedIndent({ except: /^{/ }), - JSXElement(context) { - let closed = /^\s*<\//.test(context.textAfter); - return context.lineIndent(context.node.from) + (closed ? 0 : context.unit); - }, - JSXEscape(context) { - let closed = /\s*\}/.test(context.textAfter); - return context.lineIndent(context.node.from) + (closed ? 0 : context.unit); - }, - "JSXOpenTag JSXSelfClosingTag"(context) { - return context.column(context.node.from) + context.unit; - } - }), - language.foldNodeProp.add({ - "Block ClassBody SwitchBody EnumBody ObjectExpression ArrayExpression": language.foldInside, - BlockComment(tree) { return { from: tree.from + 2, to: tree.to - 2 }; } - }), - highlight.styleTags({ - "get set async static": highlight.tags.modifier, - "for while do if else switch try catch finally return throw break continue default case": highlight.tags.controlKeyword, - "in of await yield void typeof delete instanceof": highlight.tags.operatorKeyword, - "let var const function class extends": highlight.tags.definitionKeyword, - "import export from": highlight.tags.moduleKeyword, - "with debugger as new": highlight.tags.keyword, - TemplateString: highlight.tags.special(highlight.tags.string), - Super: highlight.tags.atom, - BooleanLiteral: highlight.tags.bool, - this: highlight.tags.self, - null: highlight.tags.null, - Star: highlight.tags.modifier, - VariableName: highlight.tags.variableName, - "CallExpression/VariableName TaggedTemplateExpression/VariableName": highlight.tags.function(highlight.tags.variableName), - VariableDefinition: highlight.tags.definition(highlight.tags.variableName), - Label: highlight.tags.labelName, - PropertyName: highlight.tags.propertyName, - PrivatePropertyName: highlight.tags.special(highlight.tags.propertyName), - "CallExpression/MemberExpression/PropertyName": highlight.tags.function(highlight.tags.propertyName), - "FunctionDeclaration/VariableDefinition": highlight.tags.function(highlight.tags.definition(highlight.tags.variableName)), - "ClassDeclaration/VariableDefinition": highlight.tags.definition(highlight.tags.className), - PropertyDefinition: highlight.tags.definition(highlight.tags.propertyName), - PrivatePropertyDefinition: highlight.tags.definition(highlight.tags.special(highlight.tags.propertyName)), - UpdateOp: highlight.tags.updateOperator, - LineComment: highlight.tags.lineComment, - BlockComment: highlight.tags.blockComment, - Number: highlight.tags.number, - String: highlight.tags.string, - ArithOp: highlight.tags.arithmeticOperator, - LogicOp: highlight.tags.logicOperator, - BitOp: highlight.tags.bitwiseOperator, - CompareOp: highlight.tags.compareOperator, - RegExp: highlight.tags.regexp, - Equals: highlight.tags.definitionOperator, - "Arrow : Spread": highlight.tags.punctuation, - "( )": highlight.tags.paren, - "[ ]": highlight.tags.squareBracket, - "{ }": highlight.tags.brace, - "InterpolationStart InterpolationEnd": highlight.tags.special(highlight.tags.brace), - ".": highlight.tags.derefOperator, - ", ;": highlight.tags.separator, - TypeName: highlight.tags.typeName, - TypeDefinition: highlight.tags.definition(highlight.tags.typeName), - "type enum interface implements namespace module declare": highlight.tags.definitionKeyword, - "abstract global Privacy readonly override": highlight.tags.modifier, - "is keyof unique infer": highlight.tags.operatorKeyword, - JSXAttributeValue: highlight.tags.attributeValue, - JSXText: highlight.tags.content, - "JSXStartTag JSXStartCloseTag JSXSelfCloseEndTag JSXEndTag": highlight.tags.angleBracket, - "JSXIdentifier JSXNameSpacedName": highlight.tags.tagName, - "JSXAttribute/JSXIdentifier JSXAttribute/JSXNameSpacedName": highlight.tags.attributeName - }) - ] - }), - languageData: { - closeBrackets: { brackets: ["(", "[", "{", "'", '"', "`"] }, - commentTokens: { line: "//", block: { open: "/*", close: "*/" } }, - indentOnInput: /^\s*(?:case |default:|\{|\}|<\/)$/, - wordChars: "$" + Check whether these changes touch a given range. When one of the + changes entirely covers the range, the string `"cover"` is + returned. + */ + touchesRange(from, to = from) { + for (let i = 0, pos = 0; i < this.sections.length && pos <= to;) { + let len = this.sections[i++], ins = this.sections[i++], end = pos + len; + if (ins >= 0 && pos <= to && end >= from) + return pos < from && end > to ? "cover" : true; + pos = end; + } + return false; + } + /** + @internal + */ + toString() { + let result = ""; + for (let i = 0; i < this.sections.length;) { + let len = this.sections[i++], ins = this.sections[i++]; + result += (result ? " " : "") + len + (ins >= 0 ? ":" + ins : ""); + } + return result; + } + /** + Serialize this change desc to a JSON-representable value. + */ + toJSON() { return this.sections; } + /** + Create a change desc from its JSON representation (as produced + by [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeDesc.toJSON). + */ + static fromJSON(json) { + if (!Array.isArray(json) || json.length % 2 || json.some(a => typeof a != "number")) + throw new RangeError("Invalid JSON representation of ChangeDesc"); + return new ChangeDesc(json); } -}); -/** -A language provider for TypeScript. -*/ -const typescriptLanguage = javascriptLanguage.configure({ dialect: "ts" }); -/** -Language provider for JSX. -*/ -const jsxLanguage = javascriptLanguage.configure({ dialect: "jsx" }); -/** -Language provider for JSX + TypeScript. -*/ -const tsxLanguage = javascriptLanguage.configure({ dialect: "jsx ts" }); -/** -JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets) -completion. -*/ -function javascript(config = {}) { - let lang = config.jsx ? (config.typescript ? tsxLanguage : jsxLanguage) - : config.typescript ? typescriptLanguage : javascriptLanguage; - return new language.LanguageSupport(lang, javascriptLanguage.data.of({ - autocomplete: autocomplete.ifNotIn(["LineComment", "BlockComment", "String"], autocomplete.completeFromList(snippets)) - })); } - /** -Connects an [ESLint](https://eslint.org/) linter to CodeMirror's -[lint](https://codemirror.net/6/docs/ref/#lint) integration. `eslint` should be an instance of the -[`Linter`](https://eslint.org/docs/developer-guide/nodejs-api#linter) -class, and `config` an optional ESLint configuration. The return -value of this function can be passed to [`linter`](https://codemirror.net/6/docs/ref/#lint.linter) -to create a JavaScript linting extension. - -Note that ESLint targets node, and is tricky to run in the -browser. The [eslint4b](https://github.com/mysticatea/eslint4b) -and -[eslint4b-prebuilt](https://github.com/marijnh/eslint4b-prebuilt/) -packages may help with that. +A change set represents a group of modifications to a document. It +stores the document length, and can only be applied to documents +with exactly that length. */ -function esLint(eslint, config) { - if (!config) { - config = { - parserOptions: { ecmaVersion: 2019, sourceType: "module" }, - env: { browser: true, node: true, es6: true, es2015: true, es2017: true, es2020: true }, - rules: {} - }; - eslint.getRules().forEach((desc, name) => { - if (desc.meta.docs.recommended) - config.rules[name] = 2; - }); +class ChangeSet extends ChangeDesc { + /** + @internal + */ + constructor(sections, + /** + @internal + */ + inserted) { + super(sections); + this.inserted = inserted; } - return (view) => { - let { state } = view, found = []; - for (let { from, to } of javascriptLanguage.findRegions(state)) { - let fromLine = state.doc.lineAt(from), offset = { line: fromLine.number - 1, col: from - fromLine.from, pos: from }; - for (let d of eslint.verify(state.sliceDoc(from, to), config)) - found.push(translateDiagnostic(d, state.doc, offset)); + /** + Apply the changes to a document, returning the modified + document. + */ + apply(doc) { + if (this.length != doc.length) + throw new RangeError("Applying change set to a document with the wrong length"); + iterChanges(this, (fromA, toA, fromB, _toB, text) => doc = doc.replace(fromB, fromB + (toA - fromA), text), false); + return doc; + } + mapDesc(other, before = false) { return mapSet(this, other, before, true); } + /** + Given the document as it existed _before_ the changes, return a + change set that represents the inverse of this set, which could + be used to go from the document created by the changes back to + the document as it existed before the changes. + */ + invert(doc) { + let sections = this.sections.slice(), inserted = []; + for (let i = 0, pos = 0; i < sections.length; i += 2) { + let len = sections[i], ins = sections[i + 1]; + if (ins >= 0) { + sections[i] = ins; + sections[i + 1] = len; + let index = i >> 1; + while (inserted.length < index) + inserted.push(text.Text.empty); + inserted.push(len ? doc.slice(pos, pos + len) : text.Text.empty); + } + pos += len; } - return found; - }; + return new ChangeSet(sections, inserted); + } + /** + Combine two subsequent change sets into a single set. `other` + must start in the document produced by `this`. If `this` goes + `docA` → `docB` and `other` represents `docB` → `docC`, the + returned value will represent the change `docA` → `docC`. + */ + compose(other) { return this.empty ? other : other.empty ? this : composeSets(this, other, true); } + /** + Given another change set starting in the same document, maps this + change set over the other, producing a new change set that can be + applied to the document produced by applying `other`. When + `before` is `true`, order changes as if `this` comes before + `other`, otherwise (the default) treat `other` as coming first. + + Given two changes `A` and `B`, `A.compose(B.map(A))` and + `B.compose(A.map(B, true))` will produce the same document. This + provides a basic form of [operational + transformation](https://en.wikipedia.org/wiki/Operational_transformation), + and can be used for collaborative editing. + */ + map(other, before = false) { return other.empty ? this : mapSet(this, other, before, true); } + /** + Iterate over the changed ranges in the document, calling `f` for + each. + + When `individual` is true, adjacent changes are reported + separately. + */ + iterChanges(f, individual = false) { + iterChanges(this, f, individual); + } + /** + Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change + set. + */ + get desc() { return new ChangeDesc(this.sections); } + /** + @internal + */ + filter(ranges) { + let resultSections = [], resultInserted = [], filteredSections = []; + let iter = new SectionIter(this); + done: for (let i = 0, pos = 0;;) { + let next = i == ranges.length ? 1e9 : ranges[i++]; + while (pos < next || pos == next && iter.len == 0) { + if (iter.done) + break done; + let len = Math.min(iter.len, next - pos); + addSection(filteredSections, len, -1); + let ins = iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0; + addSection(resultSections, len, ins); + if (ins > 0) + addInsert(resultInserted, resultSections, iter.text); + iter.forward(len); + pos += len; + } + let end = ranges[i++]; + while (pos < end) { + if (iter.done) + break done; + let len = Math.min(iter.len, end - pos); + addSection(resultSections, len, -1); + addSection(filteredSections, len, iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0); + iter.forward(len); + pos += len; + } + } + return { changes: new ChangeSet(resultSections, resultInserted), + filtered: new ChangeDesc(filteredSections) }; + } + /** + Serialize this change set to a JSON-representable value. + */ + toJSON() { + let parts = []; + for (let i = 0; i < this.sections.length; i += 2) { + let len = this.sections[i], ins = this.sections[i + 1]; + if (ins < 0) + parts.push(len); + else if (ins == 0) + parts.push([len]); + else + parts.push([len].concat(this.inserted[i >> 1].toJSON())); + } + return parts; + } + /** + Create a change set for the given changes, for a document of the + given length, using `lineSep` as line separator. + */ + static of(changes, length, lineSep) { + let sections = [], inserted = [], pos = 0; + let total = null; + function flush(force = false) { + if (!force && !sections.length) + return; + if (pos < length) + addSection(sections, length - pos, -1); + let set = new ChangeSet(sections, inserted); + total = total ? total.compose(set.map(total)) : set; + sections = []; + inserted = []; + pos = 0; + } + function process(spec) { + if (Array.isArray(spec)) { + for (let sub of spec) + process(sub); + } + else if (spec instanceof ChangeSet) { + if (spec.length != length) + throw new RangeError(`Mismatched change set length (got ${spec.length}, expected ${length})`); + flush(); + total = total ? total.compose(spec.map(total)) : spec; + } + else { + let { from, to = from, insert } = spec; + if (from > to || from < 0 || to > length) + throw new RangeError(`Invalid change range ${from} to ${to} (in doc of length ${length})`); + let insText = !insert ? text.Text.empty : typeof insert == "string" ? text.Text.of(insert.split(lineSep || DefaultSplit)) : insert; + let insLen = insText.length; + if (from == to && insLen == 0) + return; + if (from < pos) + flush(); + if (from > pos) + addSection(sections, from - pos, -1); + addSection(sections, to - from, insLen); + addInsert(inserted, sections, insText); + pos = to; + } + } + process(changes); + flush(!total); + return total; + } + /** + Create an empty changeset of the given length. + */ + static empty(length) { + return new ChangeSet(length ? [length, -1] : [], []); + } + /** + Create a changeset from its JSON representation (as produced by + [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeSet.toJSON). + */ + static fromJSON(json) { + if (!Array.isArray(json)) + throw new RangeError("Invalid JSON representation of ChangeSet"); + let sections = [], inserted = []; + for (let i = 0; i < json.length; i++) { + let part = json[i]; + if (typeof part == "number") { + sections.push(part, -1); + } + else if (!Array.isArray(part) || typeof part[0] != "number" || part.some((e, i) => i && typeof e != "string")) { + throw new RangeError("Invalid JSON representation of ChangeSet"); + } + else if (part.length == 1) { + sections.push(part[0], 0); + } + else { + while (inserted.length < i) + inserted.push(text.Text.empty); + inserted[i] = text.Text.of(part.slice(1)); + sections.push(part[0], inserted[i].length); + } + } + return new ChangeSet(sections, inserted); + } } -function mapPos(line, col, doc, offset) { - return doc.line(line + offset.line).from + col + (line == 1 ? offset.col - 1 : -1); +function addSection(sections, len, ins, forceJoin = false) { + if (len == 0 && ins <= 0) + return; + let last = sections.length - 2; + if (last >= 0 && ins <= 0 && ins == sections[last + 1]) + sections[last] += len; + else if (len == 0 && sections[last] == 0) + sections[last + 1] += ins; + else if (forceJoin) { + sections[last] += len; + sections[last + 1] += ins; + } + else + sections.push(len, ins); } -function translateDiagnostic(input, doc, offset) { - let start = mapPos(input.line, input.column, doc, offset); - let result = { - from: start, - to: input.endLine != null && input.endColumn != 1 ? mapPos(input.endLine, input.endColumn, doc, offset) : start, - message: input.message, - source: input.ruleId ? "jshint:" + input.ruleId : "jshint", - severity: input.severity == 1 ? "warning" : "error", - }; - if (input.fix) { - let { range, text } = input.fix, from = range[0] + offset.pos - start, to = range[1] + offset.pos - start; - result.actions = [{ - name: "fix", - apply(view, start) { - view.dispatch({ changes: { from: start + from, to: start + to, insert: text }, scrollIntoView: true }); +function addInsert(values, sections, value) { + if (value.length == 0) + return; + let index = (sections.length - 2) >> 1; + if (index < values.length) { + values[values.length - 1] = values[values.length - 1].append(value); + } + else { + while (values.length < index) + values.push(text.Text.empty); + values.push(value); + } +} +function iterChanges(desc, f, individual) { + let inserted = desc.inserted; + for (let posA = 0, posB = 0, i = 0; i < desc.sections.length;) { + let len = desc.sections[i++], ins = desc.sections[i++]; + if (ins < 0) { + posA += len; + posB += len; + } + else { + let endA = posA, endB = posB, text$1 = text.Text.empty; + for (;;) { + endA += len; + endB += ins; + if (ins && inserted) + text$1 = text$1.append(inserted[(i - 2) >> 1]); + if (individual || i == desc.sections.length || desc.sections[i + 1] < 0) + break; + len = desc.sections[i++]; + ins = desc.sections[i++]; + } + f(posA, endA, posB, endB, text$1); + posA = endA; + posB = endB; + } + } +} +function mapSet(setA, setB, before, mkSet = false) { + let sections = [], insert = mkSet ? [] : null; + let a = new SectionIter(setA), b = new SectionIter(setB); + for (let posA = 0, posB = 0;;) { + if (a.ins == -1) { + posA += a.len; + a.next(); + } + else if (b.ins == -1 && posB < posA) { + let skip = Math.min(b.len, posA - posB); + b.forward(skip); + addSection(sections, skip, -1); + posB += skip; + } + else if (b.ins >= 0 && (a.done || posB < posA || posB == posA && (b.len < a.len || b.len == a.len && !before))) { + addSection(sections, b.ins, -1); + while (posA > posB && !a.done && posA + a.len < posB + b.len) { + posA += a.len; + a.next(); + } + posB += b.len; + b.next(); + } + else if (a.ins >= 0) { + let len = 0, end = posA + a.len; + for (;;) { + if (b.ins >= 0 && posB > posA && posB + b.len < end) { + len += b.ins; + posB += b.len; + b.next(); } - }]; + else if (b.ins == -1 && posB < end) { + let skip = Math.min(b.len, end - posB); + len += skip; + b.forward(skip); + posB += skip; + } + else { + break; + } + } + addSection(sections, len, a.ins); + if (insert) + addInsert(insert, sections, a.text); + posA = end; + a.next(); + } + else if (a.done && b.done) { + return insert ? new ChangeSet(sections, insert) : new ChangeDesc(sections); + } + else { + throw new Error("Mismatched change set lengths"); + } + } +} +function composeSets(setA, setB, mkSet = false) { + let sections = []; + let insert = mkSet ? [] : null; + let a = new SectionIter(setA), b = new SectionIter(setB); + for (let open = false;;) { + if (a.done && b.done) { + return insert ? new ChangeSet(sections, insert) : new ChangeDesc(sections); + } + else if (a.ins == 0) { // Deletion in A + addSection(sections, a.len, 0, open); + a.next(); + } + else if (b.len == 0 && !b.done) { // Insertion in B + addSection(sections, 0, b.ins, open); + if (insert) + addInsert(insert, sections, b.text); + b.next(); + } + else if (a.done || b.done) { + throw new Error("Mismatched change set lengths"); + } + else { + let len = Math.min(a.len2, b.len), sectionLen = sections.length; + if (a.ins == -1) { + let insB = b.ins == -1 ? -1 : b.off ? 0 : b.ins; + addSection(sections, len, insB, open); + if (insert && insB) + addInsert(insert, sections, b.text); + } + else if (b.ins == -1) { + addSection(sections, a.off ? 0 : a.len, len, open); + if (insert) + addInsert(insert, sections, a.textBit(len)); + } + else { + addSection(sections, a.off ? 0 : a.len, b.off ? 0 : b.ins, open); + if (insert && !b.off) + addInsert(insert, sections, b.text); + } + open = (a.ins > len || b.ins >= 0 && b.len > len) && (open || sections.length > sectionLen); + a.forward2(len); + b.forward(len); + } + } +} +class SectionIter { + constructor(set) { + this.set = set; + this.i = 0; + this.next(); + } + next() { + let { sections } = this.set; + if (this.i < sections.length) { + this.len = sections[this.i++]; + this.ins = sections[this.i++]; + } + else { + this.len = 0; + this.ins = -2; + } + this.off = 0; + } + get done() { return this.ins == -2; } + get len2() { return this.ins < 0 ? this.len : this.ins; } + get text() { + let { inserted } = this.set, index = (this.i - 2) >> 1; + return index >= inserted.length ? text.Text.empty : inserted[index]; + } + textBit(len) { + let { inserted } = this.set, index = (this.i - 2) >> 1; + return index >= inserted.length && !len ? text.Text.empty + : inserted[index].slice(this.off, len == null ? undefined : this.off + len); + } + forward(len) { + if (len == this.len) + this.next(); + else { + this.len -= len; + this.off += len; + } + } + forward2(len) { + if (this.ins == -1) + this.forward(len); + else if (len == this.ins) + this.next(); + else { + this.ins -= len; + this.off += len; + } } - return result; } -exports.esLint = esLint; -exports.javascript = javascript; -exports.javascriptLanguage = javascriptLanguage; -exports.jsxLanguage = jsxLanguage; -exports.snippets = snippets; -exports.tsxLanguage = tsxLanguage; -exports.typescriptLanguage = typescriptLanguage; - -},{"@codemirror/autocomplete":44,"@codemirror/highlight":46,"@codemirror/language":48,"@lezer/javascript":56}],48:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var common = require('@lezer/common'); -var state = require('@codemirror/state'); -var view = require('@codemirror/view'); -var text = require('@codemirror/text'); - -/** -Node prop stored in a grammar's top syntax node to provide the -facet that stores language data for that language. -*/ -const languageDataProp = new common.NodeProp(); /** -Helper function to define a facet (to be added to the top syntax -node(s) for a language via -[`languageDataProp`](https://codemirror.net/6/docs/ref/#language.languageDataProp)), that will be -used to associate language data with the language. You -probably only need this when subclassing -[`Language`](https://codemirror.net/6/docs/ref/#language.Language). +A single selection range. When +[`allowMultipleSelections`](https://codemirror.net/6/docs/ref/#state.EditorState^allowMultipleSelections) +is enabled, a [selection](https://codemirror.net/6/docs/ref/#state.EditorSelection) may hold +multiple ranges. By default, selections hold exactly one range. */ -function defineLanguageFacet(baseData) { - return state.Facet.define({ - combine: baseData ? values => values.concat(baseData) : undefined - }); +class SelectionRange { + /** + @internal + */ + constructor( + /** + The lower boundary of the range. + */ + from, + /** + The upper boundary of the range. + */ + to, flags) { + this.from = from; + this.to = to; + this.flags = flags; + } + /** + The anchor of the range—the side that doesn't move when you + extend it. + */ + get anchor() { return this.flags & 16 /* Inverted */ ? this.to : this.from; } + /** + The head of the range, which is moved when the range is + [extended](https://codemirror.net/6/docs/ref/#state.SelectionRange.extend). + */ + get head() { return this.flags & 16 /* Inverted */ ? this.from : this.to; } + /** + True when `anchor` and `head` are at the same position. + */ + get empty() { return this.from == this.to; } + /** + If this is a cursor that is explicitly associated with the + character on one of its sides, this returns the side. -1 means + the character before its position, 1 the character after, and 0 + means no association. + */ + get assoc() { return this.flags & 4 /* AssocBefore */ ? -1 : this.flags & 8 /* AssocAfter */ ? 1 : 0; } + /** + The bidirectional text level associated with this cursor, if + any. + */ + get bidiLevel() { + let level = this.flags & 3 /* BidiLevelMask */; + return level == 3 ? null : level; + } + /** + The goal column (stored vertical offset) associated with a + cursor. This is used to preserve the vertical position when + [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across + lines of different length. + */ + get goalColumn() { + let value = this.flags >> 5 /* GoalColumnOffset */; + return value == 33554431 /* NoGoalColumn */ ? undefined : value; + } + /** + Map this range through a change, producing a valid range in the + updated document. + */ + map(change, assoc = -1) { + let from = change.mapPos(this.from, assoc), to = change.mapPos(this.to, assoc); + return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags); + } + /** + Extend this range to cover at least `from` to `to`. + */ + extend(from, to = from) { + if (from <= this.anchor && to >= this.anchor) + return EditorSelection.range(from, to); + let head = Math.abs(from - this.anchor) > Math.abs(to - this.anchor) ? from : to; + return EditorSelection.range(this.anchor, head); + } + /** + Compare this range to another range. + */ + eq(other) { + return this.anchor == other.anchor && this.head == other.head; + } + /** + Return a JSON-serializable object representing the range. + */ + toJSON() { return { anchor: this.anchor, head: this.head }; } + /** + Convert a JSON representation of a range to a `SelectionRange` + instance. + */ + static fromJSON(json) { + if (!json || typeof json.anchor != "number" || typeof json.head != "number") + throw new RangeError("Invalid JSON representation for SelectionRange"); + return EditorSelection.range(json.anchor, json.head); + } } /** -A language object manages parsing and per-language -[metadata](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt). Parse data is -managed as a [Lezer](https://lezer.codemirror.net) tree. You'll -want to subclass this class for custom parsers, or use the -[`LRLanguage`](https://codemirror.net/6/docs/ref/#language.LRLanguage) or -[`StreamLanguage`](https://codemirror.net/6/docs/ref/#stream-parser.StreamLanguage) abstractions for -[Lezer](https://lezer.codemirror.net/) or stream parsers. +An editor selection holds one or more selection ranges. */ -class Language { +class EditorSelection { /** - Construct a language object. You usually don't need to invoke - this directly. But when you do, make sure you use - [`defineLanguageFacet`](https://codemirror.net/6/docs/ref/#language.defineLanguageFacet) to create - the first argument. + @internal */ constructor( /** - The [language data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) data - facet used for this language. + The ranges in the selection, sorted by position. Ranges cannot + overlap (but they may touch, if they aren't empty). */ - data, parser, + ranges, /** - The node type of the top node of trees produced by this parser. + The index of the _main_ range in the selection (which is + usually the range that was added last). */ - topNode, extraExtensions = []) { - this.data = data; - this.topNode = topNode; - // Kludge to define EditorState.tree as a debugging helper, - // without the EditorState package actually knowing about - // languages and lezer trees. - if (!state.EditorState.prototype.hasOwnProperty("tree")) - Object.defineProperty(state.EditorState.prototype, "tree", { get() { return syntaxTree(this); } }); - this.parser = parser; - this.extension = [ - language.of(this), - state.EditorState.languageData.of((state, pos, side) => state.facet(languageDataFacetAt(state, pos, side))) - ].concat(extraExtensions); + mainIndex = 0) { + this.ranges = ranges; + this.mainIndex = mainIndex; } /** - Query whether this language is active at the given position. + Map a selection through a change. Used to adjust the selection + position for changes. */ - isActiveAt(state, pos, side = -1) { - return languageDataFacetAt(state, pos, side) == this.data; + map(change, assoc = -1) { + if (change.empty) + return this; + return EditorSelection.create(this.ranges.map(r => r.map(change, assoc)), this.mainIndex); } /** - Find the document regions that were parsed using this language. - The returned regions will _include_ any nested languages rooted - in this language, when those exist. + Compare this selection to another selection. */ - findRegions(state) { - let lang = state.facet(language); - if ((lang === null || lang === void 0 ? void 0 : lang.data) == this.data) - return [{ from: 0, to: state.doc.length }]; - if (!lang || !lang.allowsNesting) - return []; - let result = []; - let explore = (tree, from) => { - if (tree.prop(languageDataProp) == this.data) { - result.push({ from, to: from + tree.length }); - return; - } - let mount = tree.prop(common.NodeProp.mounted); - if (mount) { - if (mount.tree.prop(languageDataProp) == this.data) { - if (mount.overlay) - for (let r of mount.overlay) - result.push({ from: r.from + from, to: r.to + from }); - else - result.push({ from: from, to: from + tree.length }); - return; - } - else if (mount.overlay) { - let size = result.length; - explore(mount.tree, mount.overlay[0].from + from); - if (result.length > size) - return; - } - } - for (let i = 0; i < tree.children.length; i++) { - let ch = tree.children[i]; - if (ch instanceof common.Tree) - explore(ch, tree.positions[i] + from); - } - }; - explore(syntaxTree(state), 0); - return result; + eq(other) { + if (this.ranges.length != other.ranges.length || + this.mainIndex != other.mainIndex) + return false; + for (let i = 0; i < this.ranges.length; i++) + if (!this.ranges[i].eq(other.ranges[i])) + return false; + return true; } /** - Indicates whether this language allows nested languages. The - default implementation returns true. + Get the primary selection range. Usually, you should make sure + your code applies to _all_ ranges, by using methods like + [`changeByRange`](https://codemirror.net/6/docs/ref/#state.EditorState.changeByRange). */ - get allowsNesting() { return true; } + get main() { return this.ranges[this.mainIndex]; } + /** + Make sure the selection only has one range. Returns a selection + holding only the main range from this selection. + */ + asSingle() { + return this.ranges.length == 1 ? this : new EditorSelection([this.main]); + } + /** + Extend this selection with an extra range. + */ + addRange(range, main = true) { + return EditorSelection.create([range].concat(this.ranges), main ? 0 : this.mainIndex + 1); + } + /** + Replace a given range with another range, and then normalize the + selection to merge and sort ranges if necessary. + */ + replaceRange(range, which = this.mainIndex) { + let ranges = this.ranges.slice(); + ranges[which] = range; + return EditorSelection.create(ranges, this.mainIndex); + } + /** + Convert this selection to an object that can be serialized to + JSON. + */ + toJSON() { + return { ranges: this.ranges.map(r => r.toJSON()), main: this.mainIndex }; + } + /** + Create a selection from a JSON representation. + */ + static fromJSON(json) { + if (!json || !Array.isArray(json.ranges) || typeof json.main != "number" || json.main >= json.ranges.length) + throw new RangeError("Invalid JSON representation for EditorSelection"); + return new EditorSelection(json.ranges.map((r) => SelectionRange.fromJSON(r)), json.main); + } + /** + Create a selection holding a single range. + */ + static single(anchor, head = anchor) { + return new EditorSelection([EditorSelection.range(anchor, head)], 0); + } + /** + Sort and merge the given set of ranges, creating a valid + selection. + */ + static create(ranges, mainIndex = 0) { + if (ranges.length == 0) + throw new RangeError("A selection needs at least one range"); + for (let pos = 0, i = 0; i < ranges.length; i++) { + let range = ranges[i]; + if (range.empty ? range.from <= pos : range.from < pos) + return normalized(ranges.slice(), mainIndex); + pos = range.to; + } + return new EditorSelection(ranges, mainIndex); + } + /** + Create a cursor selection range at the given position. You can + safely ignore the optional arguments in most situations. + */ + static cursor(pos, assoc = 0, bidiLevel, goalColumn) { + return new SelectionRange(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 4 /* AssocBefore */ : 8 /* AssocAfter */) | + (bidiLevel == null ? 3 : Math.min(2, bidiLevel)) | + ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* NoGoalColumn */) << 5 /* GoalColumnOffset */)); + } + /** + Create a selection range. + */ + static range(anchor, head, goalColumn) { + let goal = (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* NoGoalColumn */) << 5 /* GoalColumnOffset */; + return head < anchor ? new SelectionRange(head, anchor, 16 /* Inverted */ | goal) : new SelectionRange(anchor, head, goal); + } } -/** -@internal -*/ -Language.setState = state.StateEffect.define(); -function languageDataFacetAt(state, pos, side) { - let topLang = state.facet(language); - if (!topLang) - return null; - let facet = topLang.data; - if (topLang.allowsNesting) { - for (let node = syntaxTree(state).topNode; node; node = node.enter(pos, side, true, false)) - facet = node.type.prop(languageDataProp) || facet; +function normalized(ranges, mainIndex = 0) { + let main = ranges[mainIndex]; + ranges.sort((a, b) => a.from - b.from); + mainIndex = ranges.indexOf(main); + for (let i = 1; i < ranges.length; i++) { + let range = ranges[i], prev = ranges[i - 1]; + if (range.empty ? range.from <= prev.to : range.from < prev.to) { + let from = prev.from, to = Math.max(range.to, prev.to); + if (i <= mainIndex) + mainIndex--; + ranges.splice(--i, 2, range.anchor > range.head ? EditorSelection.range(to, from) : EditorSelection.range(from, to)); + } } - return facet; + return new EditorSelection(ranges, mainIndex); } +function checkSelection(selection, docLength) { + for (let range of selection.ranges) + if (range.to > docLength) + throw new RangeError("Selection points outside of document"); +} + +let nextID = 0; /** -A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer -[LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser) -parsers. +A facet is a labeled value that is associated with an editor +state. It takes inputs from any number of extensions, and combines +those into a single output value. + +Examples of facets are the [theme](https://codemirror.net/6/docs/ref/#view.EditorView^theme) styles +associated with an editor or the [tab +size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) (which is reduced to a single +value, using the input with the hightest precedence). */ -class LRLanguage extends Language { - constructor(data, parser) { - super(data, parser, parser.topNode); - this.parser = parser; +class Facet { + constructor( + /** + @internal + */ + combine, + /** + @internal + */ + compareInput, + /** + @internal + */ + compare, isStatic, + /** + @internal + */ + extensions) { + this.combine = combine; + this.compareInput = compareInput; + this.compare = compare; + this.isStatic = isStatic; + this.extensions = extensions; + /** + @internal + */ + this.id = nextID++; + this.default = combine([]); } /** - Define a language from a parser. + Define a new facet. */ - static define(spec) { - let data = defineLanguageFacet(spec.languageData); - return new LRLanguage(data, spec.parser.configure({ - props: [languageDataProp.add(type => type.isTop ? data : undefined)] - })); + static define(config = {}) { + return new Facet(config.combine || ((a) => a), config.compareInput || ((a, b) => a === b), config.compare || (!config.combine ? sameArray : (a, b) => a === b), !!config.static, config.enables); } /** - Create a new instance of this language with a reconfigured - version of its parser. + Returns an extension that adds the given value for this facet. */ - configure(options) { - return new LRLanguage(this.data, this.parser.configure(options)); + of(value) { + return new FacetProvider([], this, 0 /* Static */, value); + } + /** + Create an extension that computes a value for the facet from a + state. You must take care to declare the parts of the state that + this value depends on, since your function is only called again + for a new state when one of those parts changed. + + In most cases, you'll want to use the + [`provide`](https://codemirror.net/6/docs/ref/#state.StateField^define^config.provide) option when + defining a field instead. + */ + compute(deps, get) { + if (this.isStatic) + throw new Error("Can't compute a static facet"); + return new FacetProvider(deps, this, 1 /* Single */, get); + } + /** + Create an extension that computes zero or more values for this + facet from a state. + */ + computeN(deps, get) { + if (this.isStatic) + throw new Error("Can't compute a static facet"); + return new FacetProvider(deps, this, 2 /* Multi */, get); + } + from(field, get) { + if (!get) + get = x => x; + return this.compute([field], state => get(state.field(field))); } - get allowsNesting() { return this.parser.wrappers.length > 0; } // FIXME -} -/** -Get the syntax tree for a state, which is the current (possibly -incomplete) parse tree of active [language](https://codemirror.net/6/docs/ref/#language.Language), -or the empty tree if there is no language available. -*/ -function syntaxTree(state) { - let field = state.field(Language.state, false); - return field ? field.tree : common.Tree.empty; } -/** -Try to get a parse tree that spans at least up to `upto`. The -method will do at most `timeout` milliseconds of work to parse -up to that point if the tree isn't already available. -*/ -function ensureSyntaxTree(state, upto, timeout = 50) { - var _a; - let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context; - return !parse ? null : parse.isDone(upto) || parse.work(timeout, upto) ? parse.tree : null; +function sameArray(a, b) { + return a == b || a.length == b.length && a.every((e, i) => e === b[i]); } -/** -Queries whether there is a full syntax tree available up to the -given document position. If there isn't, the background parse -process _might_ still be working and update the tree further, but -there is no guarantee of that—the parser will [stop -working](https://codemirror.net/6/docs/ref/#language.syntaxParserStopped) when it has spent a -certain amount of time or has moved beyond the visible viewport. -Always returns false if no language has been enabled. -*/ -function syntaxTreeAvailable(state, upto = state.doc.length) { - var _a; - return ((_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context.isDone(upto)) || false; +class FacetProvider { + constructor(dependencies, facet, type, value) { + this.dependencies = dependencies; + this.facet = facet; + this.type = type; + this.value = value; + this.id = nextID++; + } + dynamicSlot(addresses) { + var _a; + let getter = this.value; + let compare = this.facet.compareInput; + let idx = addresses[this.id] >> 1, multi = this.type == 2 /* Multi */; + let depDoc = false, depSel = false, depAddrs = []; + for (let dep of this.dependencies) { + if (dep == "doc") + depDoc = true; + else if (dep == "selection") + depSel = true; + else if ((((_a = addresses[dep.id]) !== null && _a !== void 0 ? _a : 1) & 1) == 0) + depAddrs.push(addresses[dep.id]); + } + return (state, tr) => { + let oldVal = state.values[idx]; + if (oldVal === Uninitialized) { + state.values[idx] = getter(state); + return 1 /* Changed */; + } + if (tr) { + let depChanged = (depDoc && tr.docChanged) || (depSel && (tr.docChanged || tr.selection)) || + depAddrs.some(addr => (ensureAddr(state, addr) & 1 /* Changed */) > 0); + if (depChanged) { + let newVal = getter(state); + if (multi ? !compareArray(newVal, oldVal, compare) : !compare(newVal, oldVal)) { + state.values[idx] = newVal; + return 1 /* Changed */; + } + } + } + return 0; + }; + } } -/** -Tells you whether the language parser is planning to do more -parsing work (in a `requestIdleCallback` pseudo-thread) or has -stopped running, either because it parsed the entire document, -because it spent too much time and was cut off, or because there -is no language parser enabled. -*/ -function syntaxParserRunning(view) { - var _a; - return ((_a = view.plugin(parseWorker)) === null || _a === void 0 ? void 0 : _a.isWorking()) || false; +function compareArray(a, b, compare) { + if (a.length != b.length) + return false; + for (let i = 0; i < a.length; i++) + if (!compare(a[i], b[i])) + return false; + return true; } -// Lezer-style Input object for a Text document. -class DocInput { - constructor(doc, length = doc.length) { - this.doc = doc; - this.length = length; - this.cursorPos = 0; - this.string = ""; - this.cursor = doc.iter(); - } - syncTo(pos) { - this.string = this.cursor.next(pos - this.cursorPos).value; - this.cursorPos = pos + this.string.length; - return this.cursorPos - this.string.length; - } - chunk(pos) { - this.syncTo(pos); - return this.string; - } - get lineChunks() { return true; } - read(from, to) { - let stringStart = this.cursorPos - this.string.length; - if (from < stringStart || to >= this.cursorPos) - return this.doc.sliceString(from, to); - else - return this.string.slice(from - stringStart, to - stringStart); - } +function dynamicFacetSlot(addresses, facet, providers) { + let providerAddrs = providers.map(p => addresses[p.id]); + let providerTypes = providers.map(p => p.type); + let dynamic = providerAddrs.filter(p => !(p & 1)); + let idx = addresses[facet.id] >> 1; + return (state, tr) => { + let oldVal = state.values[idx], changed = oldVal === Uninitialized || !tr; + for (let dynAddr of dynamic) { + if (ensureAddr(state, dynAddr) & 1 /* Changed */) + changed = true; + } + if (!changed) + return 0; + let values = []; + for (let i = 0; i < providerAddrs.length; i++) { + let value = getAddr(state, providerAddrs[i]); + if (providerTypes[i] == 2 /* Multi */) + for (let val of value) + values.push(val); + else + values.push(value); + } + let value = facet.combine(values); + if (oldVal !== Uninitialized && facet.compare(value, oldVal)) + return 0; + state.values[idx] = value; + return 1 /* Changed */; + }; } -let currentContext = null; +const initField = Facet.define({ static: true }); /** -A parse context provided to parsers working on the editor content. +Fields can store additional information in an editor state, and +keep it in sync with the rest of the state. */ -class ParseContext { - /** - @internal - */ - constructor(parser, - /** - The current editor state. - */ - state, - /** - Tree fragments that can be reused by incremental re-parses. - */ - fragments = [], +class StateField { + constructor( /** @internal */ - tree, treeLen, - /** - The current editor viewport (or some overapproximation - thereof). Intended to be used for opportunistically avoiding - work (in which case - [`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.ParseContext.skipUntilInView) - should be called to make sure the parser is restarted when the - skipped region becomes visible). - */ - viewport, + id, createF, updateF, compareF, /** @internal */ - skipped, - /** - This is where skipping parsers can register a promise that, - when resolved, will schedule a new parse. It is cleared when - the parse worker picks up the promise. @internal - */ - scheduleOn) { - this.parser = parser; - this.state = state; - this.fragments = fragments; - this.tree = tree; - this.treeLen = treeLen; - this.viewport = viewport; - this.skipped = skipped; - this.scheduleOn = scheduleOn; - this.parse = null; + spec) { + this.id = id; + this.createF = createF; + this.updateF = updateF; + this.compareF = compareF; + this.spec = spec; /** @internal */ - this.tempSkipped = []; + this.provides = undefined; } - startParse() { - return this.parser.startParse(new DocInput(this.state.doc), this.fragments); + /** + Define a state field. + */ + static define(config) { + let field = new StateField(nextID++, config.create, config.update, config.compare || ((a, b) => a === b), config); + if (config.provide) + field.provides = config.provide(field); + return field; + } + create(state) { + let init = state.facet(initField).find(i => i.field == this); + return ((init === null || init === void 0 ? void 0 : init.create) || this.createF)(state); } /** @internal */ - work(time, upto) { - if (upto != null && upto >= this.state.doc.length) - upto = undefined; - if (this.tree != common.Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) { - this.takeTree(); - return true; - } - return this.withContext(() => { - var _a; - let endTime = Date.now() + time; - if (!this.parse) - this.parse = this.startParse(); - if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) && - upto < this.state.doc.length) - this.parse.stopAt(upto); - for (;;) { - let done = this.parse.advance(); - if (done) { - this.fragments = this.withoutTempSkipped(common.TreeFragment.addTree(done, this.fragments, this.parse.stoppedAt != null)); - this.treeLen = (_a = this.parse.stoppedAt) !== null && _a !== void 0 ? _a : this.state.doc.length; - this.tree = done; - this.parse = null; - if (this.treeLen < (upto !== null && upto !== void 0 ? upto : this.state.doc.length)) - this.parse = this.startParse(); - else - return true; + slot(addresses) { + let idx = addresses[this.id] >> 1; + return (state, tr) => { + let oldVal = state.values[idx]; + if (oldVal === Uninitialized) { + state.values[idx] = this.create(state); + return 1 /* Changed */; + } + if (tr) { + let value = this.updateF(oldVal, tr); + if (!this.compareF(oldVal, value)) { + state.values[idx] = value; + return 1 /* Changed */; } - if (Date.now() > endTime) - return false; } - }); + return 0; + }; } /** - @internal + Returns an extension that enables this field and overrides the + way it is initialized. Can be useful when you need to provide a + non-default starting value for the field. */ - takeTree() { - let pos, tree; - if (this.parse && (pos = this.parse.parsedPos) >= this.treeLen) { - if (this.parse.stoppedAt == null || this.parse.stoppedAt > pos) - this.parse.stopAt(pos); - this.withContext(() => { while (!(tree = this.parse.advance())) { } }); - this.treeLen = pos; - this.tree = tree; - this.fragments = this.withoutTempSkipped(common.TreeFragment.addTree(this.tree, this.fragments, true)); - this.parse = null; - } - } - withContext(f) { - let prev = currentContext; - currentContext = this; - try { - return f(); - } - finally { - currentContext = prev; - } - } - withoutTempSkipped(fragments) { - for (let r; r = this.tempSkipped.pop();) - fragments = cutFragments(fragments, r.from, r.to); - return fragments; + init(create) { + return [this, initField.of({ field: this, create })]; } /** - @internal + State field instances can be used as + [`Extension`](https://codemirror.net/6/docs/ref/#state.Extension) values to enable the field in a + given state. */ - changes(changes, newState) { - let { fragments, tree, treeLen, viewport, skipped } = this; - this.takeTree(); - if (!changes.empty) { - let ranges = []; - changes.iterChangedRanges((fromA, toA, fromB, toB) => ranges.push({ fromA, toA, fromB, toB })); - fragments = common.TreeFragment.applyChanges(fragments, ranges); - tree = common.Tree.empty; - treeLen = 0; - viewport = { from: changes.mapPos(viewport.from, -1), to: changes.mapPos(viewport.to, 1) }; - if (this.skipped.length) { - skipped = []; - for (let r of this.skipped) { - let from = changes.mapPos(r.from, 1), to = changes.mapPos(r.to, -1); - if (from < to) - skipped.push({ from, to }); - } - } - } - return new ParseContext(this.parser, newState, fragments, tree, treeLen, viewport, skipped, this.scheduleOn); - } + get extension() { return this; } +} +const Prec_ = { lowest: 4, low: 3, default: 2, high: 1, highest: 0 }; +function prec(value) { + return (ext) => new PrecExtension(ext, value); +} +/** +By default extensions are registered in the order they are found +in the flattened form of nested array that was provided. +Individual extension values can be assigned a precedence to +override this. Extensions that do not have a precedence set get +the precedence of the nearest parent with a precedence, or +[`default`](https://codemirror.net/6/docs/ref/#state.Prec.default) if there is no such parent. The +final ordering of extensions is determined by first sorting by +precedence and then by order within each precedence. +*/ +const Prec = { /** - @internal + The lowest precedence level. Meant for things that should end up + near the end of the extension order. */ - updateViewport(viewport) { - if (this.viewport.from == viewport.from && this.viewport.to == viewport.to) - return false; - this.viewport = viewport; - let startLen = this.skipped.length; - for (let i = 0; i < this.skipped.length; i++) { - let { from, to } = this.skipped[i]; - if (from < viewport.to && to > viewport.from) { - this.fragments = cutFragments(this.fragments, from, to); - this.skipped.splice(i--, 1); - } - } - if (this.skipped.length >= startLen) - return false; - this.reset(); - return true; - } + lowest: prec(Prec_.lowest), /** - @internal + A lower-than-default precedence, for extensions. */ - reset() { - if (this.parse) { - this.takeTree(); - this.parse = null; - } - } + low: prec(Prec_.low), /** - Notify the parse scheduler that the given region was skipped - because it wasn't in view, and the parse should be restarted - when it comes into view. + The default precedence, which is also used for extensions + without an explicit precedence. */ - skipUntilInView(from, to) { - this.skipped.push({ from, to }); - } + default: prec(Prec_.default), /** - Returns a parser intended to be used as placeholder when - asynchronously loading a nested parser. It'll skip its input and - mark it as not-really-parsed, so that the next update will parse - it again. - - When `until` is given, a reparse will be scheduled when that - promise resolves. + A higher-than-default precedence, for extensions that should + come before those with default precedence. */ - static getSkippingParser(until) { - return new class extends common.Parser { - createParse(input, fragments, ranges) { - let from = ranges[0].from, to = ranges[ranges.length - 1].to; - let parser = { - parsedPos: from, - advance() { - let cx = currentContext; - if (cx) { - for (let r of ranges) - cx.tempSkipped.push(r); - if (until) - cx.scheduleOn = cx.scheduleOn ? Promise.all([cx.scheduleOn, until]) : until; - } - this.parsedPos = to; - return new common.Tree(common.NodeType.none, [], [], to - from); - }, - stoppedAt: null, - stopAt() { } - }; - return parser; - } - }; - } + high: prec(Prec_.high), /** - @internal + The highest precedence level, for extensions that should end up + near the start of the precedence ordering. */ - isDone(upto) { - upto = Math.min(upto, this.state.doc.length); - let frags = this.fragments; - return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto; - } + highest: prec(Prec_.highest), + // FIXME Drop these in some future breaking version /** - Get the context for the current parse, or `null` if no editor - parse is in progress. + Backwards-compatible synonym for `Prec.lowest`. */ - static get() { return currentContext; } -} -function cutFragments(fragments, from, to) { - return common.TreeFragment.applyChanges(fragments, [{ fromA: from, toA: to, fromB: from, toB: to }]); + fallback: prec(Prec_.lowest), + /** + Backwards-compatible synonym for `Prec.high`. + */ + extend: prec(Prec_.high), + /** + Backwards-compatible synonym for `Prec.highest`. + */ + override: prec(Prec_.highest) +}; +class PrecExtension { + constructor(inner, prec) { + this.inner = inner; + this.prec = prec; + } } -class LanguageState { - constructor( - // A mutable parse state that is used to preserve work done during - // the lifetime of a state when moving to the next state. - context) { - this.context = context; - this.tree = context.tree; +/** +Extension compartments can be used to make a configuration +dynamic. By [wrapping](https://codemirror.net/6/docs/ref/#state.Compartment.of) part of your +configuration in a compartment, you can later +[replace](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) that part through a +transaction. +*/ +class Compartment { + /** + Create an instance of this compartment to add to your [state + configuration](https://codemirror.net/6/docs/ref/#state.EditorStateConfig.extensions). + */ + of(ext) { return new CompartmentInstance(this, ext); } + /** + Create an [effect](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) that + reconfigures this compartment. + */ + reconfigure(content) { + return Compartment.reconfigure.of({ compartment: this, extension: content }); } - apply(tr) { - if (!tr.docChanged) - return this; - let newCx = this.context.changes(tr.changes, tr.state); - // If the previous parse wasn't done, go forward only up to its - // end position or the end of the viewport, to avoid slowing down - // state updates with parse work beyond the viewport. - let upto = this.context.treeLen == tr.startState.doc.length ? undefined - : Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to); - if (!newCx.work(20 /* Apply */, upto)) - newCx.takeTree(); - return new LanguageState(newCx); + /** + Get the current content of the compartment in the state, or + `undefined` if it isn't present. + */ + get(state) { + return state.config.compartments.get(this); } - static init(state) { - let vpTo = Math.min(3000 /* InitViewport */, state.doc.length); - let parseState = new ParseContext(state.facet(language).parser, state, [], common.Tree.empty, 0, { from: 0, to: vpTo }, [], null); - if (!parseState.work(20 /* Apply */, vpTo)) - parseState.takeTree(); - return new LanguageState(parseState); +} +class CompartmentInstance { + constructor(compartment, inner) { + this.compartment = compartment; + this.inner = inner; } } -Language.state = state.StateField.define({ - create: LanguageState.init, - update(value, tr) { - for (let e of tr.effects) - if (e.is(Language.setState)) - return e.value; - if (tr.startState.facet(language) != tr.state.facet(language)) - return LanguageState.init(tr.state); - return value.apply(tr); +class Configuration { + constructor(base, compartments, dynamicSlots, address, staticValues) { + this.base = base; + this.compartments = compartments; + this.dynamicSlots = dynamicSlots; + this.address = address; + this.staticValues = staticValues; + this.statusTemplate = []; + while (this.statusTemplate.length < dynamicSlots.length) + this.statusTemplate.push(0 /* Unresolved */); } -}); -let requestIdle = (callback) => { - let timeout = setTimeout(() => callback(), 500 /* MaxPause */); - return () => clearTimeout(timeout); -}; -if (typeof requestIdleCallback != "undefined") - requestIdle = (callback) => { - let idle = -1, timeout = setTimeout(() => { - idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ }); - }, 100 /* MinPause */); - return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle); - }; -const parseWorker = view.ViewPlugin.fromClass(class ParseWorker { - constructor(view) { - this.view = view; - this.working = null; - this.workScheduled = 0; - // End of the current time chunk - this.chunkEnd = -1; - // Milliseconds of budget left for this chunk - this.chunkBudget = -1; - this.work = this.work.bind(this); - this.scheduleWork(); + staticFacet(facet) { + let addr = this.address[facet.id]; + return addr == null ? facet.default : this.staticValues[addr >> 1]; } - update(update) { - let cx = this.view.state.field(Language.state).context; - if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen) - this.scheduleWork(); - if (update.docChanged) { - if (this.view.hasFocus) - this.chunkBudget += 50 /* ChangeBonus */; - this.scheduleWork(); + static resolve(base, compartments, oldState) { + let fields = []; + let facets = Object.create(null); + let newCompartments = new Map(); + for (let ext of flatten(base, compartments, newCompartments)) { + if (ext instanceof StateField) + fields.push(ext); + else + (facets[ext.facet.id] || (facets[ext.facet.id] = [])).push(ext); + } + let address = Object.create(null); + let staticValues = []; + let dynamicSlots = []; + let dynamicDeps = []; + for (let field of fields) { + address[field.id] = dynamicSlots.length << 1; + dynamicSlots.push(a => field.slot(a)); + dynamicDeps.push([]); + } + for (let id in facets) { + let providers = facets[id], facet = providers[0].facet; + if (providers.every(p => p.type == 0 /* Static */)) { + address[facet.id] = (staticValues.length << 1) | 1; + let value = facet.combine(providers.map(p => p.value)); + let oldAddr = oldState ? oldState.config.address[facet.id] : null; + if (oldAddr != null) { + let oldVal = getAddr(oldState, oldAddr); + if (facet.compare(value, oldVal)) + value = oldVal; + } + staticValues.push(value); + } + else { + for (let p of providers) { + if (p.type == 0 /* Static */) { + address[p.id] = (staticValues.length << 1) | 1; + staticValues.push(p.value); + } + else { + address[p.id] = dynamicSlots.length << 1; + dynamicSlots.push(a => p.dynamicSlot(a)); + dynamicDeps.push(p.dependencies.filter(d => typeof d != "string").map(d => d.id)); + } + } + address[facet.id] = dynamicSlots.length << 1; + dynamicSlots.push(a => dynamicFacetSlot(a, facet, providers)); + dynamicDeps.push(providers.filter(p => p.type != 0 /* Static */).map(d => d.id)); + } } - this.checkAsyncSchedule(cx); - } - scheduleWork() { - if (this.working) - return; - let { state } = this.view, field = state.field(Language.state); - if (field.tree != field.context.tree || !field.context.isDone(state.doc.length)) - this.working = requestIdle(this.work); + let dynamicValues = dynamicSlots.map(_ => Uninitialized); + if (oldState) { + let canReuse = (id, depth) => { + if (depth > 7) + return false; + let addr = address[id]; + if (!(addr & 1)) + return dynamicDeps[addr >> 1].every(id => canReuse(id, depth + 1)); + let oldAddr = oldState.config.address[id]; + return oldAddr != null && getAddr(oldState, oldAddr) == staticValues[addr >> 1]; + }; + // Copy over old values for shared facets/fields, if we can + // prove that they don't need to be recomputed. + for (let id in address) { + let cur = address[id], prev = oldState.config.address[id]; + if (prev != null && (cur & 1) == 0 && canReuse(+id, 0)) + dynamicValues[cur >> 1] = getAddr(oldState, prev); + } + } + return { + configuration: new Configuration(base, newCompartments, dynamicSlots.map(f => f(address)), address, staticValues), + values: dynamicValues + }; } - work(deadline) { - this.working = null; - let now = Date.now(); - if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk - this.chunkEnd = now + 30000 /* ChunkTime */; - this.chunkBudget = 3000 /* ChunkBudget */; +} +function flatten(extension, compartments, newCompartments) { + let result = [[], [], [], [], []]; + let seen = new Map(); + function inner(ext, prec) { + let known = seen.get(ext); + if (known != null) { + if (known >= prec) + return; + let found = result[known].indexOf(ext); + if (found > -1) + result[known].splice(found, 1); + if (ext instanceof CompartmentInstance) + newCompartments.delete(ext.compartment); } - if (this.chunkBudget <= 0) - return; // No more budget - let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state); - if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */)) - return; - let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9); - let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000; - let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */)); - this.chunkBudget -= Date.now() - now; - if (done || this.chunkBudget <= 0) { - field.context.takeTree(); - this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) }); + seen.set(ext, prec); + if (Array.isArray(ext)) { + for (let e of ext) + inner(e, prec); } - if (this.chunkBudget > 0 && !(done && !viewportFirst)) - this.scheduleWork(); - this.checkAsyncSchedule(field.context); - } - checkAsyncSchedule(cx) { - if (cx.scheduleOn) { - this.workScheduled++; - cx.scheduleOn - .then(() => this.scheduleWork()) - .catch(err => view.logException(this.view.state, err)) - .then(() => this.workScheduled--); - cx.scheduleOn = null; + else if (ext instanceof CompartmentInstance) { + if (newCompartments.has(ext.compartment)) + throw new RangeError(`Duplicate use of compartment in extensions`); + let content = compartments.get(ext.compartment) || ext.inner; + newCompartments.set(ext.compartment, content); + inner(content, prec); + } + else if (ext instanceof PrecExtension) { + inner(ext.inner, ext.prec); + } + else if (ext instanceof StateField) { + result[prec].push(ext); + if (ext.provides) + inner(ext.provides, prec); + } + else if (ext instanceof FacetProvider) { + result[prec].push(ext); + if (ext.facet.extensions) + inner(ext.facet.extensions, prec); + } + else { + let content = ext.extension; + if (!content) + throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`); + inner(content, prec); } } - destroy() { - if (this.working) - this.working(); - } - isWorking() { - return this.working || this.workScheduled > 0; - } -}, { - eventHandlers: { focus() { this.scheduleWork(); } } + inner(extension, Prec_.default); + return result.reduce((a, b) => a.concat(b)); +} +const Uninitialized = {}; +function ensureAddr(state, addr) { + if (addr & 1) + return 2 /* Computed */; + let idx = addr >> 1; + let status = state.status[idx]; + if (status == 4 /* Computing */) + throw new Error("Cyclic dependency between fields and/or facets"); + if (status & 2 /* Computed */) + return status; + state.status[idx] = 4 /* Computing */; + let changed = state.config.dynamicSlots[idx](state, state.applying); + return state.status[idx] = 2 /* Computed */ | changed; +} +function getAddr(state, addr) { + return addr & 1 ? state.config.staticValues[addr >> 1] : state.values[addr >> 1]; +} + +const languageData = Facet.define(); +const allowMultipleSelections = Facet.define({ + combine: values => values.some(v => v), + static: true }); -/** -The facet used to associate a language with an editor state. -*/ -const language = state.Facet.define({ - combine(languages) { return languages.length ? languages[0] : null; }, - enables: [Language.state, parseWorker] +const lineSeparator = Facet.define({ + combine: values => values.length ? values[0] : undefined, + static: true +}); +const changeFilter = Facet.define(); +const transactionFilter = Facet.define(); +const transactionExtender = Facet.define(); +const readOnly = Facet.define({ + combine: values => values.length ? values[0] : false }); + /** -This class bundles a [language object](https://codemirror.net/6/docs/ref/#language.Language) with an -optional set of supporting extensions. Language packages are -encouraged to export a function that optionally takes a -configuration object and returns a `LanguageSupport` instance, as -the main way for client code to use the package. +Annotations are tagged values that are used to add metadata to +transactions in an extensible way. They should be used to model +things that effect the entire transaction (such as its [time +stamp](https://codemirror.net/6/docs/ref/#state.Transaction^time) or information about its +[origin](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent)). For effects that happen +_alongside_ the other changes made by the transaction, [state +effects](https://codemirror.net/6/docs/ref/#state.StateEffect) are more appropriate. */ -class LanguageSupport { +class Annotation { /** - Create a support object. + @internal */ constructor( /** - The language object. + The annotation type. */ - language, + type, /** - An optional set of supporting extensions. When nesting a - language in another language, the outer language is encouraged - to include the supporting extensions for its inner languages - in its own set of support extensions. + The value of this annotation. */ - support = []) { - this.language = language; - this.support = support; - this.extension = [language, support]; + value) { + this.type = type; + this.value = value; } + /** + Define a new type of annotation. + */ + static define() { return new AnnotationType(); } } /** -Language descriptions are used to store metadata about languages -and to dynamically load them. Their main role is finding the -appropriate language for a filename or dynamically loading nested -parsers. +Marker that identifies a type of [annotation](https://codemirror.net/6/docs/ref/#state.Annotation). */ -class LanguageDescription { - constructor( - /** - The name of this language. - */ - name, - /** - Alternative names for the mode (lowercased, includes `this.name`). - */ - alias, - /** - File extensions associated with this language. - */ - extensions, - /** - Optional filename pattern that should be associated with this - language. - */ - filename, loadFunc, - /** - If the language has been loaded, this will hold its value. - */ - support = undefined) { - this.name = name; - this.alias = alias; - this.extensions = extensions; - this.filename = filename; - this.loadFunc = loadFunc; - this.support = support; - this.loading = null; - } +class AnnotationType { /** - Start loading the the language. Will return a promise that - resolves to a [`LanguageSupport`](https://codemirror.net/6/docs/ref/#language.LanguageSupport) - object when the language successfully loads. + Create an instance of this annotation. */ - load() { - return this.loading || (this.loading = this.loadFunc().then(support => this.support = support, err => { this.loading = null; throw err; })); - } + of(value) { return new Annotation(this, value); } +} +/** +Representation of a type of state effect. Defined with +[`StateEffect.define`](https://codemirror.net/6/docs/ref/#state.StateEffect^define). +*/ +class StateEffectType { /** - Create a language description. + @internal */ - static of(spec) { - let { load, support } = spec; - if (!load) { - if (!support) - throw new RangeError("Must pass either 'load' or 'support' to LanguageDescription.of"); - load = () => Promise.resolve(support); - } - return new LanguageDescription(spec.name, (spec.alias || []).concat(spec.name).map(s => s.toLowerCase()), spec.extensions || [], spec.filename, load, support); - } + constructor( + // The `any` types in these function types are there to work + // around TypeScript issue #37631, where the type guard on + // `StateEffect.is` mysteriously stops working when these properly + // have type `Value`. /** - Look for a language in the given array of descriptions that - matches the filename. Will first match - [`filename`](https://codemirror.net/6/docs/ref/#language.LanguageDescription.filename) patterns, - and then [extensions](https://codemirror.net/6/docs/ref/#language.LanguageDescription.extensions), - and return the first language that matches. + @internal */ - static matchFilename(descs, filename) { - for (let d of descs) - if (d.filename && d.filename.test(filename)) - return d; - let ext = /\.([^.]+)$/.exec(filename); - if (ext) - for (let d of descs) - if (d.extensions.indexOf(ext[1]) > -1) - return d; - return null; + map) { + this.map = map; } /** - Look for a language whose name or alias matches the the given - name (case-insensitively). If `fuzzy` is true, and no direct - matchs is found, this'll also search for a language whose name - or alias occurs in the string (for names shorter than three - characters, only when surrounded by non-word characters). + Create a [state effect](https://codemirror.net/6/docs/ref/#state.StateEffect) instance of this + type. */ - static matchLanguageName(descs, name, fuzzy = true) { - name = name.toLowerCase(); - for (let d of descs) - if (d.alias.some(a => a == name)) - return d; - if (fuzzy) - for (let d of descs) - for (let a of d.alias) { - let found = name.indexOf(a); - if (found > -1 && (a.length > 2 || !/\w/.test(name[found - 1]) && !/\w/.test(name[found + a.length]))) - return d; - } - return null; - } -} - -/** -Facet that defines a way to provide a function that computes the -appropriate indentation depth at the start of a given line, or -`null` to indicate no appropriate indentation could be determined. -*/ -const indentService = state.Facet.define(); -/** -Facet for overriding the unit by which indentation happens. -Should be a string consisting either entirely of spaces or -entirely of tabs. When not set, this defaults to 2 spaces. -*/ -const indentUnit = state.Facet.define({ - combine: values => { - if (!values.length) - return " "; - if (!/^(?: +|\t+)$/.test(values[0])) - throw new Error("Invalid indent unit: " + JSON.stringify(values[0])); - return values[0]; - } -}); -/** -Return the _column width_ of an indent unit in the state. -Determined by the [`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) -facet, and [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) when that -contains tabs. -*/ -function getIndentUnit(state) { - let unit = state.facet(indentUnit); - return unit.charCodeAt(0) == 9 ? state.tabSize * unit.length : unit.length; -} -/** -Create an indentation string that covers columns 0 to `cols`. -Will use tabs for as much of the columns as possible when the -[`indentUnit`](https://codemirror.net/6/docs/ref/#language.indentUnit) facet contains -tabs. -*/ -function indentString(state, cols) { - let result = "", ts = state.tabSize; - if (state.facet(indentUnit).charCodeAt(0) == 9) - while (cols >= ts) { - result += "\t"; - cols -= ts; - } - for (let i = 0; i < cols; i++) - result += " "; - return result; -} -/** -Get the indentation at the given position. Will first consult any -[indent services](https://codemirror.net/6/docs/ref/#language.indentService) that are registered, -and if none of those return an indentation, this will check the -syntax tree for the [indent node prop](https://codemirror.net/6/docs/ref/#language.indentNodeProp) -and use that if found. Returns a number when an indentation could -be determined, and null otherwise. -*/ -function getIndentation(context, pos) { - if (context instanceof state.EditorState) - context = new IndentContext(context); - for (let service of context.state.facet(indentService)) { - let result = service(context, pos); - if (result != null) - return result; - } - let tree = syntaxTree(context.state); - return tree ? syntaxIndentation(context, tree, pos) : null; + of(value) { return new StateEffect(this, value); } } /** -Indentation contexts are used when calling [indentation -services](https://codemirror.net/6/docs/ref/#language.indentService). They provide helper utilities -useful in indentation logic, and can selectively override the -indentation reported for some lines. +State effects can be used to represent additional effects +associated with a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction.effects). They +are often useful to model changes to custom [state +fields](https://codemirror.net/6/docs/ref/#state.StateField), when those changes aren't implicit in +document or selection changes. */ -class IndentContext { +class StateEffect { /** - Create an indent context. + @internal */ constructor( /** - The editor state. - */ - state, - /** @internal */ - options = {}) { - this.state = state; - this.options = options; - this.unit = getIndentUnit(state); - } + type, /** - Get a description of the line at the given position, taking - [simulated line - breaks](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) - into account. If there is such a break at `pos`, the `bias` - argument determines whether the part of the line line before or - after the break is used. + The value of this effect. */ - lineAt(pos, bias = 1) { - let line = this.state.doc.lineAt(pos); - let { simulateBreak } = this.options; - if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) { - if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos) - return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak }; - else - return { text: line.text.slice(0, simulateBreak - line.from), from: line.from }; - } - return line; + value) { + this.type = type; + this.value = value; } /** - Get the text directly after `pos`, either the entire line - or the next 100 characters, whichever is shorter. + Map this effect through a position mapping. Will return + `undefined` when that ends up deleting the effect. */ - textAfterPos(pos, bias = 1) { - if (this.options.simulateDoubleBreak && pos == this.options.simulateBreak) - return ""; - let { text, from } = this.lineAt(pos, bias); - return text.slice(pos - from, Math.min(text.length, pos + 100 - from)); + map(mapping) { + let mapped = this.type.map(this.value, mapping); + return mapped === undefined ? undefined : mapped == this.value ? this : new StateEffect(this.type, mapped); } /** - Find the column for the given position. + Tells you whether this effect object is of a given + [type](https://codemirror.net/6/docs/ref/#state.StateEffectType). */ - column(pos, bias = 1) { - let { text, from } = this.lineAt(pos, bias); - let result = this.countColumn(text, pos - from); - let override = this.options.overrideIndentation ? this.options.overrideIndentation(from) : -1; - if (override > -1) - result += override - this.countColumn(text, text.search(/\S|$/)); - return result; - } + is(type) { return this.type == type; } /** - Find the column position (taking tabs into account) of the given - position in the given string. + Define a new effect type. The type parameter indicates the type + of values that his effect holds. */ - countColumn(line, pos = line.length) { - return text.countColumn(line, this.state.tabSize, pos); + static define(spec = {}) { + return new StateEffectType(spec.map || (v => v)); } /** - Find the indentation column of the line at the given point. + Map an array of effects through a change set. */ - lineIndent(pos, bias = 1) { - let { text, from } = this.lineAt(pos, bias); - let override = this.options.overrideIndentation; - if (override) { - let overriden = override(from); - if (overriden > -1) - return overriden; + static mapEffects(effects, mapping) { + if (!effects.length) + return effects; + let result = []; + for (let effect of effects) { + let mapped = effect.map(mapping); + if (mapped) + result.push(mapped); } - return this.countColumn(text, text.search(/\S|$/)); - } - /** - Returns the [simulated line - break](https://codemirror.net/6/docs/ref/#language.IndentContext.constructor^options.simulateBreak) - for this context, if any. - */ - get simulatedBreak() { - return this.options.simulateBreak || null; + return result; } } /** -A syntax tree node prop used to associate indentation strategies -with node types. Such a strategy is a function from an indentation -context to a column number or null, where null indicates that no -definitive indentation can be determined. +This effect can be used to reconfigure the root extensions of +the editor. Doing this will discard any extensions +[appended](https://codemirror.net/6/docs/ref/#state.StateEffect^appendConfig), but does not reset +the content of [reconfigured](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) +compartments. */ -const indentNodeProp = new common.NodeProp(); -// Compute the indentation for a given position from the syntax tree. -function syntaxIndentation(cx, ast, pos) { - return indentFrom(ast.resolveInner(pos).enterUnfinishedNodesBefore(pos), pos, cx); -} -function ignoreClosed(cx) { - return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak; -} -function indentStrategy(tree) { - let strategy = tree.type.prop(indentNodeProp); - if (strategy) - return strategy; - let first = tree.firstChild, close; - if (first && (close = first.type.prop(common.NodeProp.closedBy))) { - let last = tree.lastChild, closed = last && close.indexOf(last.name) > -1; - return cx => delimitedStrategy(cx, true, 1, undefined, closed && !ignoreClosed(cx) ? last.from : undefined); - } - return tree.parent == null ? topIndent : null; -} -function indentFrom(node, pos, base) { - for (; node; node = node.parent) { - let strategy = indentStrategy(node); - if (strategy) - return strategy(new TreeIndentContext(base, pos, node)); - } - return null; -} -function topIndent() { return 0; } +StateEffect.reconfigure = StateEffect.define(); /** -Objects of this type provide context information and helper -methods to indentation functions. +Append extensions to the top-level configuration of the editor. */ -class TreeIndentContext extends IndentContext { +StateEffect.appendConfig = StateEffect.define(); +/** +Changes to the editor state are grouped into transactions. +Typically, a user action creates a single transaction, which may +contain any number of document changes, may change the selection, +or have other effects. Create a transaction by calling +[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update). +*/ +class Transaction { /** @internal */ - constructor(base, + constructor( /** - The position at which indentation is being computed. + The state from which the transaction starts. */ - pos, + startState, /** - The syntax tree node to which the indentation strategy - applies. + The document changes made by this transaction. */ - node) { - super(base.state, base.options); - this.base = base; - this.pos = pos; - this.node = node; + changes, + /** + The selection set by this transaction, or undefined if it + doesn't explicitly set a selection. + */ + selection, + /** + The effects added to the transaction. + */ + effects, + /** + @internal + */ + annotations, + /** + Whether the selection should be scrolled into view after this + transaction is dispatched. + */ + scrollIntoView) { + this.startState = startState; + this.changes = changes; + this.selection = selection; + this.effects = effects; + this.annotations = annotations; + this.scrollIntoView = scrollIntoView; + /** + @internal + */ + this._doc = null; + /** + @internal + */ + this._state = null; + if (selection) + checkSelection(selection, changes.newLength); + if (!annotations.some((a) => a.type == Transaction.time)) + this.annotations = annotations.concat(Transaction.time.of(Date.now())); } /** - Get the text directly after `this.pos`, either the entire line - or the next 100 characters, whichever is shorter. + The new document produced by the transaction. Contrary to + [`.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state)`.doc`, accessing this won't + force the entire new state to be computed right away, so it is + recommended that [transaction + filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) use this getter + when they need to look at the new document. */ - get textAfter() { - return this.textAfterPos(this.pos); + get newDoc() { + return this._doc || (this._doc = this.changes.apply(this.startState.doc)); } /** - Get the indentation at the reference line for `this.node`, which - is the line on which it starts, unless there is a node that is - _not_ a parent of this node covering the start of that line. If - so, the line at the start of that node is tried, again skipping - on if it is covered by another such node. + The new selection produced by the transaction. If + [`this.selection`](https://codemirror.net/6/docs/ref/#state.Transaction.selection) is undefined, + this will [map](https://codemirror.net/6/docs/ref/#state.EditorSelection.map) the start state's + current selection through the changes made by the transaction. */ - get baseIndent() { - let line = this.state.doc.lineAt(this.node.from); - // Skip line starts that are covered by a sibling (or cousin, etc) - for (;;) { - let atBreak = this.node.resolve(line.from); - while (atBreak.parent && atBreak.parent.from == atBreak.from) - atBreak = atBreak.parent; - if (isParent(atBreak, this.node)) - break; - line = this.state.doc.lineAt(atBreak.from); - } - return this.lineIndent(line.from); + get newSelection() { + return this.selection || this.startState.selection.map(this.changes); } /** - Continue looking for indentations in the node's parent nodes, - and return the result of that. + The new state created by the transaction. Computed on demand + (but retained for subsequent access), so itis recommended not to + access it in [transaction + filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) when possible. */ - continue() { - let parent = this.node.parent; - return parent ? indentFrom(parent, this.pos, this.base) : 0; + get state() { + if (!this._state) + this.startState.applyTransaction(this); + return this._state; } -} -function isParent(parent, of) { - for (let cur = of; cur; cur = cur.parent) - if (parent == cur) - return true; - return false; -} -// Check whether a delimited node is aligned (meaning there are -// non-skipped nodes on the same line as the opening delimiter). And -// if so, return the opening token. -function bracketedAligned(context) { - let tree = context.node; - let openToken = tree.childAfter(tree.from), last = tree.lastChild; - if (!openToken) - return null; - let sim = context.options.simulateBreak; - let openLine = context.state.doc.lineAt(openToken.from); - let lineEnd = sim == null || sim <= openLine.from ? openLine.to : Math.min(openLine.to, sim); - for (let pos = openToken.to;;) { - let next = tree.childAfter(pos); - if (!next || next == last) - return null; - if (!next.type.isSkipped) - return next.from < lineEnd ? openToken : null; - pos = next.to; + /** + Get the value of the given annotation type, if any. + */ + annotation(type) { + for (let ann of this.annotations) + if (ann.type == type) + return ann.value; + return undefined; + } + /** + Indicates whether the transaction changed the document. + */ + get docChanged() { return !this.changes.empty; } + /** + Indicates whether this transaction reconfigures the state + (through a [configuration compartment](https://codemirror.net/6/docs/ref/#state.Compartment) or + with a top-level configuration + [effect](https://codemirror.net/6/docs/ref/#state.StateEffect^reconfigure). + */ + get reconfigured() { return this.startState.config != this.state.config; } + /** + Returns true if the transaction has a [user + event](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent) annotation that is equal to + or more specific than `event`. For example, if the transaction + has `"select.pointer"` as user event, `"select"` and + `"select.pointer"` will match it. + */ + isUserEvent(event) { + let e = this.annotation(Transaction.userEvent); + return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == ".")); } } /** -An indentation strategy for delimited (usually bracketed) nodes. -Will, by default, indent one unit more than the parent's base -indent unless the line starts with a closing token. When `align` -is true and there are non-skipped nodes on the node's opening -line, the content of the node will be aligned with the end of the -opening node, like this: - - foo(bar, - baz) -*/ -function delimitedIndent({ closing, align = true, units = 1 }) { - return (context) => delimitedStrategy(context, align, units, closing); -} -function delimitedStrategy(context, align, units, closing, closedAt) { - let after = context.textAfter, space = after.match(/^\s*/)[0].length; - let closed = closing && after.slice(space, space + closing.length) == closing || closedAt == context.pos + space; - let aligned = align ? bracketedAligned(context) : null; - if (aligned) - return closed ? context.column(aligned.from) : context.column(aligned.to); - return context.baseIndent + (closed ? 0 : context.unit * units); -} -/** -An indentation strategy that aligns a node's content to its base -indentation. -*/ -const flatIndent = (context) => context.baseIndent; -/** -Creates an indentation strategy that, by default, indents -continued lines one unit more than the node's base indentation. -You can provide `except` to prevent indentation of lines that -match a pattern (for example `/^else\b/` in `if`/`else` -constructs), and you can change the amount of units used with the -`units` option. +Annotation used to store transaction timestamps. */ -function continuedIndent({ except, units = 1 } = {}) { - return (context) => { - let matchExcept = except && except.test(context.textAfter); - return context.baseIndent + (matchExcept ? 0 : units * context.unit); - }; -} -const DontIndentBeyond = 200; +Transaction.time = Annotation.define(); /** -Enables reindentation on input. When a language defines an -`indentOnInput` field in its [language -data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt), which must hold a regular -expression, the line at the cursor will be reindented whenever new -text is typed and the input from the start of the line up to the -cursor matches that regexp. +Annotation used to associate a transaction with a user interface +event. Holds a string identifying the event, using a +dot-separated format to support attaching more specific +information. The events used by the core libraries are: -To avoid unneccesary reindents, it is recommended to start the -regexp with `^` (usually followed by `\s*`), and end it with `$`. -For example, `/^\s*\}$/` will reindent when a closing brace is -added at the start of a line. -*/ -function indentOnInput() { - return state.EditorState.transactionFilter.of(tr => { - if (!tr.docChanged || !tr.isUserEvent("input.type")) - return tr; - let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head); - if (!rules.length) - return tr; - let doc = tr.newDoc, { head } = tr.newSelection.main, line = doc.lineAt(head); - if (head > line.from + DontIndentBeyond) - return tr; - let lineStart = doc.sliceString(line.from, head); - if (!rules.some(r => r.test(lineStart))) - return tr; - let { state } = tr, last = -1, changes = []; - for (let { head } of state.selection.ranges) { - let line = state.doc.lineAt(head); - if (line.from == last) - continue; - last = line.from; - let indent = getIndentation(state, line.from); - if (indent == null) - continue; - let cur = /^\s*/.exec(line.text)[0]; - let norm = indentString(state, indent); - if (cur != norm) - changes.push({ from: line.from, to: line.from + cur.length, insert: norm }); - } - return changes.length ? [tr, { changes, sequential: true }] : tr; - }); -} + - `"input"` when content is entered + - `"input.type"` for typed input + - `"input.type.compose"` for composition + - `"input.paste"` for pasted input + - `"input.drop"` when adding content with drag-and-drop + - `"input.complete"` when autocompleting + - `"delete"` when the user deletes content + - `"delete.selection"` when deleting the selection + - `"delete.forward"` when deleting forward from the selection + - `"delete.backward"` when deleting backward from the selection + - `"delete.cut"` when cutting to the clipboard + - `"move"` when content is moved + - `"move.drop"` when content is moved within the editor through drag-and-drop + - `"select"` when explicitly changing the selection + - `"select.pointer"` when selecting with a mouse or other pointing device + - `"undo"` and `"redo"` for history actions -/** -A facet that registers a code folding service. When called with -the extent of a line, such a function should return a foldable -range that starts on that line (but continues beyond it), if one -can be found. +Use [`isUserEvent`](https://codemirror.net/6/docs/ref/#state.Transaction.isUserEvent) to check +whether the annotation matches a given event. */ -const foldService = state.Facet.define(); +Transaction.userEvent = Annotation.define(); /** -This node prop is used to associate folding information with -syntax node types. Given a syntax node, it should check whether -that tree is foldable and return the range that can be collapsed -when it is. +Annotation indicating whether a transaction should be added to +the undo history or not. */ -const foldNodeProp = new common.NodeProp(); +Transaction.addToHistory = Annotation.define(); /** -[Fold](https://codemirror.net/6/docs/ref/#language.foldNodeProp) function that folds everything but -the first and the last child of a syntax node. Useful for nodes -that start and end with delimiters. +Annotation indicating (when present and true) that a transaction +represents a change made by some other actor, not the user. This +is used, for example, to tag other people's changes in +collaborative editing. */ -function foldInside(node) { - let first = node.firstChild, last = node.lastChild; - return first && first.to < last.from ? { from: first.to, to: last.type.isError ? node.to : last.from } : null; -} -function syntaxFolding(state, start, end) { - let tree = syntaxTree(state); - if (tree.length == 0) - return null; - let inner = tree.resolveInner(end); - let found = null; - for (let cur = inner; cur; cur = cur.parent) { - if (cur.to <= end || cur.from > end) - continue; - if (found && cur.from < start) - break; - let prop = cur.type.prop(foldNodeProp); - if (prop) { - let value = prop(cur, state); - if (value && value.from <= end && value.from >= start && value.to > end) - found = value; +Transaction.remote = Annotation.define(); +function joinRanges(a, b) { + let result = []; + for (let iA = 0, iB = 0;;) { + let from, to; + if (iA < a.length && (iB == b.length || b[iB] >= a[iA])) { + from = a[iA++]; + to = a[iA++]; + } + else if (iB < b.length) { + from = b[iB++]; + to = b[iB++]; } + else + return result; + if (!result.length || result[result.length - 1] < from) + result.push(from, to); + else if (result[result.length - 1] < to) + result[result.length - 1] = to; } - return found; } -/** -Check whether the given line is foldable. First asks any fold -services registered through -[`foldService`](https://codemirror.net/6/docs/ref/#language.foldService), and if none of them return -a result, tries to query the [fold node -prop](https://codemirror.net/6/docs/ref/#language.foldNodeProp) of syntax nodes that cover the end -of the line. -*/ -function foldable(state, lineStart, lineEnd) { - for (let service of state.facet(foldService)) { - let result = service(state, lineStart, lineEnd); - if (result) - return result; +function mergeTransaction(a, b, sequential) { + var _a; + let mapForA, mapForB, changes; + if (sequential) { + mapForA = b.changes; + mapForB = ChangeSet.empty(b.changes.length); + changes = a.changes.compose(b.changes); } - return syntaxFolding(state, lineStart, lineEnd); + else { + mapForA = b.changes.map(a.changes); + mapForB = a.changes.mapDesc(b.changes, true); + changes = a.changes.compose(mapForA); + } + return { + changes, + selection: b.selection ? b.selection.map(mapForB) : (_a = a.selection) === null || _a === void 0 ? void 0 : _a.map(mapForA), + effects: StateEffect.mapEffects(a.effects, mapForA).concat(StateEffect.mapEffects(b.effects, mapForB)), + annotations: a.annotations.length ? a.annotations.concat(b.annotations) : b.annotations, + scrollIntoView: a.scrollIntoView || b.scrollIntoView + }; } - -exports.IndentContext = IndentContext; -exports.LRLanguage = LRLanguage; -exports.Language = Language; -exports.LanguageDescription = LanguageDescription; -exports.LanguageSupport = LanguageSupport; -exports.ParseContext = ParseContext; -exports.TreeIndentContext = TreeIndentContext; -exports.continuedIndent = continuedIndent; -exports.defineLanguageFacet = defineLanguageFacet; -exports.delimitedIndent = delimitedIndent; -exports.ensureSyntaxTree = ensureSyntaxTree; -exports.flatIndent = flatIndent; -exports.foldInside = foldInside; -exports.foldNodeProp = foldNodeProp; -exports.foldService = foldService; -exports.foldable = foldable; -exports.getIndentUnit = getIndentUnit; -exports.getIndentation = getIndentation; -exports.indentNodeProp = indentNodeProp; -exports.indentOnInput = indentOnInput; -exports.indentService = indentService; -exports.indentString = indentString; -exports.indentUnit = indentUnit; -exports.language = language; -exports.languageDataProp = languageDataProp; -exports.syntaxParserRunning = syntaxParserRunning; -exports.syntaxTree = syntaxTree; -exports.syntaxTreeAvailable = syntaxTreeAvailable; - -},{"@codemirror/state":51,"@codemirror/text":52,"@codemirror/view":54,"@lezer/common":55}],49:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var state = require('@codemirror/state'); -var language = require('@codemirror/language'); -var view = require('@codemirror/view'); -var common = require('@lezer/common'); - -const baseTheme = view.EditorView.baseTheme({ - "&.cm-focused .cm-matchingBracket": { backgroundColor: "#328c8252" }, - "&.cm-focused .cm-nonmatchingBracket": { backgroundColor: "#bb555544" } -}); -const DefaultScanDist = 10000, DefaultBrackets = "()[]{}"; -const bracketMatchingConfig = state.Facet.define({ - combine(configs) { - return state.combineConfig(configs, { - afterCursor: true, - brackets: DefaultBrackets, - maxScanDistance: DefaultScanDist - }); +function resolveTransactionInner(state, spec, docSize) { + let sel = spec.selection, annotations = asArray(spec.annotations); + if (spec.userEvent) + annotations = annotations.concat(Transaction.userEvent.of(spec.userEvent)); + return { + changes: spec.changes instanceof ChangeSet ? spec.changes + : ChangeSet.of(spec.changes || [], docSize, state.facet(lineSeparator)), + selection: sel && (sel instanceof EditorSelection ? sel : EditorSelection.single(sel.anchor, sel.head)), + effects: asArray(spec.effects), + annotations, + scrollIntoView: !!spec.scrollIntoView + }; +} +function resolveTransaction(state, specs, filter) { + let s = resolveTransactionInner(state, specs.length ? specs[0] : {}, state.doc.length); + if (specs.length && specs[0].filter === false) + filter = false; + for (let i = 1; i < specs.length; i++) { + if (specs[i].filter === false) + filter = false; + let seq = !!specs[i].sequential; + s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq); } -}); -const matchingMark = view.Decoration.mark({ class: "cm-matchingBracket" }), nonmatchingMark = view.Decoration.mark({ class: "cm-nonmatchingBracket" }); -const bracketMatchingState = state.StateField.define({ - create() { return view.Decoration.none; }, - update(deco, tr) { - if (!tr.docChanged && !tr.selection) - return deco; - let decorations = []; - let config = tr.state.facet(bracketMatchingConfig); - for (let range of tr.state.selection.ranges) { - if (!range.empty) - continue; - let match = matchBrackets(tr.state, range.head, -1, config) - || (range.head > 0 && matchBrackets(tr.state, range.head - 1, 1, config)) - || (config.afterCursor && - (matchBrackets(tr.state, range.head, 1, config) || - (range.head < tr.state.doc.length && matchBrackets(tr.state, range.head + 1, -1, config)))); - if (!match) - continue; - let mark = match.matched ? matchingMark : nonmatchingMark; - decorations.push(mark.range(match.start.from, match.start.to)); - if (match.end) - decorations.push(mark.range(match.end.from, match.end.to)); - } - return view.Decoration.set(decorations, true); - }, - provide: f => view.EditorView.decorations.from(f) -}); -const bracketMatchingUnique = [ - bracketMatchingState, - baseTheme -]; -/** -Create an extension that enables bracket matching. Whenever the -cursor is next to a bracket, that bracket and the one it matches -are highlighted. Or, when no matching bracket is found, another -highlighting style is used to indicate this. -*/ -function bracketMatching(config = {}) { - return [bracketMatchingConfig.of(config), bracketMatchingUnique]; + let tr = new Transaction(state, s.changes, s.selection, s.effects, s.annotations, s.scrollIntoView); + return extendTransaction(filter ? filterTransaction(tr) : tr); } -function matchingNodes(node, dir, brackets) { - let byProp = node.prop(dir < 0 ? common.NodeProp.openedBy : common.NodeProp.closedBy); - if (byProp) - return byProp; - if (node.name.length == 1) { - let index = brackets.indexOf(node.name); - if (index > -1 && index % 2 == (dir < 0 ? 1 : 0)) - return [brackets[index + dir]]; +// Finish a transaction by applying filters if necessary. +function filterTransaction(tr) { + let state = tr.startState; + // Change filters + let result = true; + for (let filter of state.facet(changeFilter)) { + let value = filter(tr); + if (value === false) { + result = false; + break; + } + if (Array.isArray(value)) + result = result === true ? value : joinRanges(result, value); + } + if (result !== true) { + let changes, back; + if (result === false) { + back = tr.changes.invertedDesc; + changes = ChangeSet.empty(state.doc.length); + } + else { + let filtered = tr.changes.filter(result); + changes = filtered.changes; + back = filtered.filtered.invertedDesc; + } + tr = new Transaction(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView); } - return null; -} -/** -Find the matching bracket for the token at `pos`, scanning -direction `dir`. Only the `brackets` and `maxScanDistance` -properties are used from `config`, if given. Returns null if no -bracket was found at `pos`, or a match result otherwise. -*/ -function matchBrackets(state, pos, dir, config = {}) { - let maxScanDistance = config.maxScanDistance || DefaultScanDist, brackets = config.brackets || DefaultBrackets; - let tree = language.syntaxTree(state), node = tree.resolveInner(pos, dir); - for (let cur = node; cur; cur = cur.parent) { - let matches = matchingNodes(cur.type, dir, brackets); - if (matches && cur.from < cur.to) - return matchMarkedBrackets(state, pos, dir, cur, matches, brackets); + // Transaction filters + let filters = state.facet(transactionFilter); + for (let i = filters.length - 1; i >= 0; i--) { + let filtered = filters[i](tr); + if (filtered instanceof Transaction) + tr = filtered; + else if (Array.isArray(filtered) && filtered.length == 1 && filtered[0] instanceof Transaction) + tr = filtered[0]; + else + tr = resolveTransaction(state, asArray(filtered), false); } - return matchPlainBrackets(state, pos, dir, tree, node.type, maxScanDistance, brackets); -} -function matchMarkedBrackets(_state, _pos, dir, token, matching, brackets) { - let parent = token.parent, firstToken = { from: token.from, to: token.to }; - let depth = 0, cursor = parent === null || parent === void 0 ? void 0 : parent.cursor; - if (cursor && (dir < 0 ? cursor.childBefore(token.from) : cursor.childAfter(token.to))) - do { - if (dir < 0 ? cursor.to <= token.from : cursor.from >= token.to) { - if (depth == 0 && matching.indexOf(cursor.type.name) > -1 && cursor.from < cursor.to) { - return { start: firstToken, end: { from: cursor.from, to: cursor.to }, matched: true }; - } - else if (matchingNodes(cursor.type, dir, brackets)) { - depth++; - } - else if (matchingNodes(cursor.type, -dir, brackets)) { - depth--; - if (depth == 0) - return { - start: firstToken, - end: cursor.from == cursor.to ? undefined : { from: cursor.from, to: cursor.to }, - matched: false - }; - } - } - } while (dir < 0 ? cursor.prevSibling() : cursor.nextSibling()); - return { start: firstToken, matched: false }; + return tr; } -function matchPlainBrackets(state, pos, dir, tree, tokenType, maxScanDistance, brackets) { - let startCh = dir < 0 ? state.sliceDoc(pos - 1, pos) : state.sliceDoc(pos, pos + 1); - let bracket = brackets.indexOf(startCh); - if (bracket < 0 || (bracket % 2 == 0) != (dir > 0)) - return null; - let startToken = { from: dir < 0 ? pos - 1 : pos, to: dir > 0 ? pos + 1 : pos }; - let iter = state.doc.iterRange(pos, dir > 0 ? state.doc.length : 0), depth = 0; - for (let distance = 0; !(iter.next()).done && distance <= maxScanDistance;) { - let text = iter.value; - if (dir < 0) - distance += text.length; - let basePos = pos + distance * dir; - for (let pos = dir > 0 ? 0 : text.length - 1, end = dir > 0 ? text.length : -1; pos != end; pos += dir) { - let found = brackets.indexOf(text[pos]); - if (found < 0 || tree.resolve(basePos + pos, 1).type != tokenType) - continue; - if ((found % 2 == 0) == (dir > 0)) { - depth++; - } - else if (depth == 1) { // Closing - return { start: startToken, end: { from: basePos + pos, to: basePos + pos + 1 }, matched: (found >> 1) == (bracket >> 1) }; - } - else { - depth--; - } - } - if (dir > 0) - distance += text.length; +function extendTransaction(tr) { + let state = tr.startState, extenders = state.facet(transactionExtender), spec = tr; + for (let i = extenders.length - 1; i >= 0; i--) { + let extension = extenders[i](tr); + if (extension && Object.keys(extension).length) + spec = mergeTransaction(tr, resolveTransactionInner(state, extension, tr.changes.newLength), true); } - return iter.done ? { start: startToken, matched: false } : null; + return spec == tr ? tr : new Transaction(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView); +} +const none = []; +function asArray(value) { + return value == null ? none : Array.isArray(value) ? value : [value]; } - -exports.bracketMatching = bracketMatching; -exports.matchBrackets = matchBrackets; - -},{"@codemirror/language":48,"@codemirror/state":51,"@codemirror/view":54,"@lezer/common":55}],50:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var state = require('@codemirror/state'); /** -Each range is associated with a value, which must inherit from -this class. +The categories produced by a [character +categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer). These are used +do things like selecting by word. */ -class RangeValue { +exports.CharCategory = void 0; +(function (CharCategory) { /** - Compare this value with another value. The default - implementation compares by identity. + Word characters. */ - eq(other) { return this == other; } + CharCategory[CharCategory["Word"] = 0] = "Word"; /** - Create a [range](https://codemirror.net/6/docs/ref/#rangeset.Range) with this value. + Whitespace. */ - range(from, to = from) { return new Range(from, to, this); } + CharCategory[CharCategory["Space"] = 1] = "Space"; + /** + Anything else. + */ + CharCategory[CharCategory["Other"] = 2] = "Other"; +})(exports.CharCategory || (exports.CharCategory = {})); +const nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; +let wordChar; +try { + wordChar = new RegExp("[\\p{Alphabetic}\\p{Number}_]", "u"); } -RangeValue.prototype.startSide = RangeValue.prototype.endSide = 0; -RangeValue.prototype.point = false; -RangeValue.prototype.mapMode = state.MapMode.TrackDel; +catch (_) { } +function hasWordChar(str) { + if (wordChar) + return wordChar.test(str); + for (let i = 0; i < str.length; i++) { + let ch = str[i]; + if (/\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))) + return true; + } + return false; +} +function makeCategorizer(wordChars) { + return (char) => { + if (!/\S/.test(char)) + return exports.CharCategory.Space; + if (hasWordChar(char)) + return exports.CharCategory.Word; + for (let i = 0; i < wordChars.length; i++) + if (char.indexOf(wordChars[i]) > -1) + return exports.CharCategory.Word; + return exports.CharCategory.Other; + }; +} + /** -A range associates a value with a range of positions. +The editor state class is a persistent (immutable) data structure. +To update a state, you [create](https://codemirror.net/6/docs/ref/#state.EditorState.update) a +[transaction](https://codemirror.net/6/docs/ref/#state.Transaction), which produces a _new_ state +instance, without modifying the original object. + +As such, _never_ mutate properties of a state directly. That'll +just break things. */ -class Range { +class EditorState { /** @internal */ constructor( /** - The range's start position. + @internal */ - from, + config, /** - Its end position. + The current document. */ - to, + doc, /** - The value associated with this range. + The current selection. */ - value) { - this.from = from; - this.to = to; - this.value = value; - } -} -function cmpRange(a, b) { - return a.from - b.from || a.value.startSide - b.value.startSide; -} -class Chunk { - constructor(from, to, value, - // Chunks are marked with the largest point that occurs - // in them (or -1 for no points), so that scans that are - // only interested in points (such as the - // heightmap-related logic) can skip range-only chunks. - maxPoint) { - this.from = from; - this.to = to; - this.value = value; - this.maxPoint = maxPoint; + selection, + /** + @internal + */ + values, tr = null) { + this.config = config; + this.doc = doc; + this.selection = selection; + this.values = values; + /** + @internal + */ + this.applying = null; + this.status = config.statusTemplate.slice(); + this.applying = tr; + // Fill in the computed state immediately, so that further queries + // for it made during the update return this state + if (tr) + tr._state = this; + for (let i = 0; i < this.config.dynamicSlots.length; i++) + ensureAddr(this, i << 1); + this.applying = null; } - get length() { return this.to[this.to.length - 1]; } - // Find the index of the given position and side. Use the ranges' - // `from` pos when `end == false`, `to` when `end == true`. - findIndex(pos, side, end, startAt = 0) { - let arr = end ? this.to : this.from; - for (let lo = startAt, hi = arr.length;;) { - if (lo == hi) - return lo; - let mid = (lo + hi) >> 1; - let diff = arr[mid] - pos || (end ? this.value[mid].endSide : this.value[mid].startSide) - side; - if (mid == lo) - return diff >= 0 ? lo : hi; - if (diff >= 0) - hi = mid; - else - lo = mid + 1; + field(field, require = true) { + let addr = this.config.address[field.id]; + if (addr == null) { + if (require) + throw new RangeError("Field is not present in this state"); + return undefined; } + ensureAddr(this, addr); + return getAddr(this, addr); } - between(offset, from, to, f) { - for (let i = this.findIndex(from, -1000000000 /* Far */, true), e = this.findIndex(to, 1000000000 /* Far */, false, i); i < e; i++) - if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false) - return false; + /** + Create a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction) that updates this + state. Any number of [transaction specs](https://codemirror.net/6/docs/ref/#state.TransactionSpec) + can be passed. Unless + [`sequential`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.sequential) is set, the + [changes](https://codemirror.net/6/docs/ref/#state.TransactionSpec.changes) (if any) of each spec + are assumed to start in the _current_ document (not the document + produced by previous specs), and its + [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) and + [effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) are assumed to refer + to the document created by its _own_ changes. The resulting + transaction contains the combined effect of all the different + specs. For [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection), later + specs take precedence over earlier ones. + */ + update(...specs) { + return resolveTransaction(this, specs, true); } - map(offset, changes) { - let value = [], from = [], to = [], newPos = -1, maxPoint = -1; - for (let i = 0; i < this.value.length; i++) { - let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo; - if (curFrom == curTo) { - let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode); - if (mapped == null) - continue; - newFrom = newTo = mapped; - if (val.startSide != val.endSide) { - newTo = changes.mapPos(curFrom, val.endSide); - if (newTo < newFrom) - continue; + /** + @internal + */ + applyTransaction(tr) { + let conf = this.config, { base, compartments } = conf; + for (let effect of tr.effects) { + if (effect.is(Compartment.reconfigure)) { + if (conf) { + compartments = new Map; + conf.compartments.forEach((val, key) => compartments.set(key, val)); + conf = null; } + compartments.set(effect.value.compartment, effect.value.extension); } - else { - newFrom = changes.mapPos(curFrom, val.startSide); - newTo = changes.mapPos(curTo, val.endSide); - if (newFrom > newTo || newFrom == newTo && val.startSide > 0 && val.endSide <= 0) - continue; + else if (effect.is(StateEffect.reconfigure)) { + conf = null; + base = effect.value; + } + else if (effect.is(StateEffect.appendConfig)) { + conf = null; + base = asArray(base).concat(effect.value); } - if ((newTo - newFrom || val.endSide - val.startSide) < 0) - continue; - if (newPos < 0) - newPos = newFrom; - if (val.point) - maxPoint = Math.max(maxPoint, newTo - newFrom); - value.push(val); - from.push(newFrom - newPos); - to.push(newTo - newPos); } - return { mapped: value.length ? new Chunk(from, to, value, maxPoint) : null, pos: newPos }; + let startValues; + if (!conf) { + let resolved = Configuration.resolve(base, compartments, this); + conf = resolved.configuration; + let intermediateState = new EditorState(conf, this.doc, this.selection, resolved.values, null); + startValues = intermediateState.values; + } + else { + startValues = tr.startState.values.slice(); + } + new EditorState(conf, tr.newDoc, tr.newSelection, startValues, tr); } -} -/** -A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#rangeset.Range) in a -way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#rangeset.RangeSet.map) and -[update](https://codemirror.net/6/docs/ref/#rangeset.RangeSet.update). This is an immutable data -structure. -*/ -class RangeSet { - /** - @internal - */ - constructor( - /** - @internal - */ - chunkPos, - /** - @internal - */ - chunk, - /** - @internal - */ - nextLayer = RangeSet.empty, /** - @internal + Create a [transaction spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec) that + replaces every selection range with the given content. */ - maxPoint) { - this.chunkPos = chunkPos; - this.chunk = chunk; - this.nextLayer = nextLayer; - this.maxPoint = maxPoint; + replaceSelection(text) { + if (typeof text == "string") + text = this.toText(text); + return this.changeByRange(range => ({ changes: { from: range.from, to: range.to, insert: text }, + range: EditorSelection.cursor(range.from + text.length) })); } /** - @internal + Create a set of changes and a new selection by running the given + function for each range in the active selection. The function + can return an optional set of changes (in the coordinate space + of the start document), plus an updated range (in the coordinate + space of the document produced by the call's own changes). This + method will merge all the changes and ranges into a single + changeset and selection, and return it as a [transaction + spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec), which can be passed to + [`update`](https://codemirror.net/6/docs/ref/#state.EditorState.update). */ - get length() { - let last = this.chunk.length - 1; - return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length); + changeByRange(f) { + let sel = this.selection; + let result1 = f(sel.ranges[0]); + let changes = this.changes(result1.changes), ranges = [result1.range]; + let effects = asArray(result1.effects); + for (let i = 1; i < sel.ranges.length; i++) { + let result = f(sel.ranges[i]); + let newChanges = this.changes(result.changes), newMapped = newChanges.map(changes); + for (let j = 0; j < i; j++) + ranges[j] = ranges[j].map(newMapped); + let mapBy = changes.mapDesc(newChanges, true); + ranges.push(result.range.map(mapBy)); + changes = changes.compose(newMapped); + effects = StateEffect.mapEffects(effects, newMapped).concat(StateEffect.mapEffects(asArray(result.effects), mapBy)); + } + return { + changes, + selection: EditorSelection.create(ranges, sel.mainIndex), + effects + }; } /** - The number of ranges in the set. + Create a [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) from the given change + description, taking the state's document length and line + separator into account. */ - get size() { - if (this.isEmpty) - return 0; - let size = this.nextLayer.size; - for (let chunk of this.chunk) - size += chunk.value.length; - return size; + changes(spec = []) { + if (spec instanceof ChangeSet) + return spec; + return ChangeSet.of(spec, this.doc.length, this.facet(EditorState.lineSeparator)); } /** - @internal + Using the state's [line + separator](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator), create a + [`Text`](https://codemirror.net/6/docs/ref/#text.Text) instance from the given string. */ - chunkEnd(index) { - return this.chunkPos[index] + this.chunk[index].length; + toText(string) { + return text.Text.of(string.split(this.facet(EditorState.lineSeparator) || DefaultSplit)); } /** - Update the range set, optionally adding new ranges or filtering - out existing ones. - - (The extra type parameter is just there as a kludge to work - around TypeScript variance issues that prevented `RangeSet` - from being a subtype of `RangeSet` when `X` is a subtype of - `Y`.) + Return the given range of the document as a string. */ - update(updateSpec) { - let { add = [], sort = false, filterFrom = 0, filterTo = this.length } = updateSpec; - let filter = updateSpec.filter; - if (add.length == 0 && !filter) - return this; - if (sort) - add.slice().sort(cmpRange); - if (this.isEmpty) - return add.length ? RangeSet.of(add) : this; - let cur = new LayerCursor(this, null, -1).goto(0), i = 0, spill = []; - let builder = new RangeSetBuilder(); - while (cur.value || i < add.length) { - if (i < add.length && (cur.from - add[i].from || cur.startSide - add[i].value.startSide) >= 0) { - let range = add[i++]; - if (!builder.addInner(range.from, range.to, range.value)) - spill.push(range); - } - else if (cur.rangeIndex == 1 && cur.chunkIndex < this.chunk.length && - (i == add.length || this.chunkEnd(cur.chunkIndex) < add[i].from) && - (!filter || filterFrom > this.chunkEnd(cur.chunkIndex) || filterTo < this.chunkPos[cur.chunkIndex]) && - builder.addChunk(this.chunkPos[cur.chunkIndex], this.chunk[cur.chunkIndex])) { - cur.nextChunk(); - } - else { - if (!filter || filterFrom > cur.to || filterTo < cur.from || filter(cur.from, cur.to, cur.value)) { - if (!builder.addInner(cur.from, cur.to, cur.value)) - spill.push(new Range(cur.from, cur.to, cur.value)); - } - cur.next(); - } - } - return builder.finishInner(this.nextLayer.isEmpty && !spill.length ? RangeSet.empty - : this.nextLayer.update({ add: spill, filter, filterFrom, filterTo })); + sliceDoc(from = 0, to = this.doc.length) { + return this.doc.sliceString(from, to, this.lineBreak); } /** - Map this range set through a set of changes, return the new set. + Get the value of a state [facet](https://codemirror.net/6/docs/ref/#state.Facet). */ - map(changes) { - if (changes.length == 0 || this.isEmpty) - return this; - let chunks = [], chunkPos = [], maxPoint = -1; - for (let i = 0; i < this.chunk.length; i++) { - let start = this.chunkPos[i], chunk = this.chunk[i]; - let touch = changes.touchesRange(start, start + chunk.length); - if (touch === false) { - maxPoint = Math.max(maxPoint, chunk.maxPoint); - chunks.push(chunk); - chunkPos.push(changes.mapPos(start)); - } - else if (touch === true) { - let { mapped, pos } = chunk.map(start, changes); - if (mapped) { - maxPoint = Math.max(maxPoint, mapped.maxPoint); - chunks.push(mapped); - chunkPos.push(pos); - } - } - } - let next = this.nextLayer.map(changes); - return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next, maxPoint); + facet(facet) { + let addr = this.config.address[facet.id]; + if (addr == null) + return facet.default; + ensureAddr(this, addr); + return getAddr(this, addr); } /** - Iterate over the ranges that touch the region `from` to `to`, - calling `f` for each. There is no guarantee that the ranges will - be reported in any specific order. When the callback returns - `false`, iteration stops. + Convert this state to a JSON-serializable object. When custom + fields should be serialized, you can pass them in as an object + mapping property names (in the resulting object, which should + not use `doc` or `selection`) to fields. */ - between(from, to, f) { - if (this.isEmpty) - return; - for (let i = 0; i < this.chunk.length; i++) { - let start = this.chunkPos[i], chunk = this.chunk[i]; - if (to >= start && from <= start + chunk.length && - chunk.between(start, from - start, to - start, f) === false) - return; - } - this.nextLayer.between(from, to, f); + toJSON(fields) { + let result = { + doc: this.sliceDoc(), + selection: this.selection.toJSON() + }; + if (fields) + for (let prop in fields) { + let value = fields[prop]; + if (value instanceof StateField) + result[prop] = value.spec.toJSON(this.field(fields[prop]), this); + } + return result; } /** - Iterate over the ranges in this set, in order, including all - ranges that end at or after `from`. + Deserialize a state from its JSON representation. When custom + fields should be deserialized, pass the same object you passed + to [`toJSON`](https://codemirror.net/6/docs/ref/#state.EditorState.toJSON) when serializing as + third argument. */ - iter(from = 0) { - return HeapCursor.from([this]).goto(from); + static fromJSON(json, config = {}, fields) { + if (!json || typeof json.doc != "string") + throw new RangeError("Invalid JSON representation for EditorState"); + let fieldInit = []; + if (fields) + for (let prop in fields) { + let field = fields[prop], value = json[prop]; + fieldInit.push(field.init(state => field.spec.fromJSON(value, state))); + } + return EditorState.create({ + doc: json.doc, + selection: EditorSelection.fromJSON(json.selection), + extensions: config.extensions ? fieldInit.concat([config.extensions]) : fieldInit + }); } /** - @internal + Create a new state. You'll usually only need this when + initializing an editor—updated states are created by applying + transactions. */ - get isEmpty() { return this.nextLayer == this; } + static create(config = {}) { + let { configuration, values } = Configuration.resolve(config.extensions || [], new Map); + let doc = config.doc instanceof text.Text ? config.doc + : text.Text.of((config.doc || "").split(configuration.staticFacet(EditorState.lineSeparator) || DefaultSplit)); + let selection = !config.selection ? EditorSelection.single(0) + : config.selection instanceof EditorSelection ? config.selection + : EditorSelection.single(config.selection.anchor, config.selection.head); + checkSelection(selection, doc.length); + if (!configuration.staticFacet(allowMultipleSelections)) + selection = selection.asSingle(); + return new EditorState(configuration, doc, selection, values); + } /** - Iterate over the ranges in a collection of sets, in order, - starting from `from`. + The size (in columns) of a tab in the document, determined by + the [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) facet. */ - static iter(sets, from = 0) { - return HeapCursor.from(sets).goto(from); - } + get tabSize() { return this.facet(EditorState.tabSize); } /** - Iterate over two groups of sets, calling methods on `comparator` - to notify it of possible differences. + Get the proper [line-break](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator) + string for this state. */ - static compare(oldSets, newSets, + get lineBreak() { return this.facet(EditorState.lineSeparator) || "\n"; } /** - This indicates how the underlying data changed between these - ranges, and is needed to synchronize the iteration. `from` and - `to` are coordinates in the _new_ space, after these changes. + Returns true when the editor is + [configured](https://codemirror.net/6/docs/ref/#state.EditorState^readOnly) to be read-only. */ - textDiff, comparator, + get readOnly() { return this.facet(readOnly); } /** - Can be used to ignore all non-point ranges, and points below - the given size. When -1, all ranges are compared. + Look up a translation for the given phrase (via the + [`phrases`](https://codemirror.net/6/docs/ref/#state.EditorState^phrases) facet), or return the + original string if no translation is found. */ - minPointSize = -1) { - let a = oldSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); - let b = newSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); - let sharedChunks = findSharedChunks(a, b, textDiff); - let sideA = new SpanCursor(a, sharedChunks, minPointSize); - let sideB = new SpanCursor(b, sharedChunks, minPointSize); - textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator)); - if (textDiff.empty && textDiff.length == 0) - compare(sideA, 0, sideB, 0, 0, comparator); + phrase(phrase) { + for (let map of this.facet(EditorState.phrases)) + if (Object.prototype.hasOwnProperty.call(map, phrase)) + return map[phrase]; + return phrase; } /** - Compare the contents of two groups of range sets, returning true - if they are equivalent in the given range. + Find the values for a given language data field, provided by the + the [`languageData`](https://codemirror.net/6/docs/ref/#state.EditorState^languageData) facet. */ - static eq(oldSets, newSets, from = 0, to) { - if (to == null) - to = 1000000000 /* Far */; - let a = oldSets.filter(set => !set.isEmpty && newSets.indexOf(set) < 0); - let b = newSets.filter(set => !set.isEmpty && oldSets.indexOf(set) < 0); - if (a.length != b.length) - return false; - if (!a.length) - return true; - let sharedChunks = findSharedChunks(a, b); - let sideA = new SpanCursor(a, sharedChunks, 0).goto(from), sideB = new SpanCursor(b, sharedChunks, 0).goto(from); - for (;;) { - if (sideA.to != sideB.to || - !sameValues(sideA.active, sideB.active) || - sideA.point && (!sideB.point || !sideA.point.eq(sideB.point))) - return false; - if (sideA.to > to) - return true; - sideA.next(); - sideB.next(); + languageDataAt(name, pos, side = -1) { + let values = []; + for (let provider of this.facet(languageData)) { + for (let result of provider(this, pos, side)) { + if (Object.prototype.hasOwnProperty.call(result, name)) + values.push(result[name]); + } } + return values; } /** - Iterate over a group of range sets at the same time, notifying - the iterator about the ranges covering every given piece of - content. Returns the open count (see - [`SpanIterator.span`](https://codemirror.net/6/docs/ref/#rangeset.SpanIterator.span)) at the end - of the iteration. + Return a function that can categorize strings (expected to + represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak)) + into one of: + + - Word (contains an alphanumeric character or a character + explicitly listed in the local language's `"wordChars"` + language data, which should be a string) + - Space (contains only whitespace) + - Other (anything else) */ - static spans(sets, from, to, iterator, + charCategorizer(at) { + return makeCategorizer(this.languageDataAt("wordChars", at).join("")); + } /** - When given and greater than -1, only points of at least this - size are taken into account. + Find the word at the given position, meaning the range + containing all [word](https://codemirror.net/6/docs/ref/#state.CharCategory.Word) characters + around it. If no word characters are adjacent to the position, + this returns null. */ - minPointSize = -1) { - var _a; - let cursor = new SpanCursor(sets, null, minPointSize, (_a = iterator.filterPoint) === null || _a === void 0 ? void 0 : _a.bind(iterator)).goto(from), pos = from; - let open = cursor.openStart; - for (;;) { - let curTo = Math.min(cursor.to, to); - if (cursor.point) { - iterator.point(pos, curTo, cursor.point, cursor.activeForPoint(cursor.to), open); - open = cursor.openEnd(curTo) + (cursor.to > curTo ? 1 : 0); - } - else if (curTo > pos) { - iterator.span(pos, curTo, cursor.active, open); - open = cursor.openEnd(curTo); + wordAt(pos) { + let { text: text$1, from, length } = this.doc.lineAt(pos); + let cat = this.charCategorizer(pos); + let start = pos - from, end = pos - from; + while (start > 0) { + let prev = text.findClusterBreak(text$1, start, false); + if (cat(text$1.slice(prev, start)) != exports.CharCategory.Word) + break; + start = prev; + } + while (end < length) { + let next = text.findClusterBreak(text$1, end); + if (cat(text$1.slice(end, next)) != exports.CharCategory.Word) + break; + end = next; + } + return start == end ? null : EditorSelection.range(start + from, end + from); + } +} +/** +A facet that, when enabled, causes the editor to allow multiple +ranges to be selected. Be careful though, because by default the +editor relies on the native DOM selection, which cannot handle +multiple selections. An extension like +[`drawSelection`](https://codemirror.net/6/docs/ref/#view.drawSelection) can be used to make +secondary selections visible to the user. +*/ +EditorState.allowMultipleSelections = allowMultipleSelections; +/** +Configures the tab size to use in this state. The first +(highest-precedence) value of the facet is used. If no value is +given, this defaults to 4. +*/ +EditorState.tabSize = Facet.define({ + combine: values => values.length ? values[0] : 4 +}); +/** +The line separator to use. By default, any of `"\n"`, `"\r\n"` +and `"\r"` is treated as a separator when splitting lines, and +lines are joined with `"\n"`. + +When you configure a value here, only that precise separator +will be used, allowing you to round-trip documents through the +editor without normalizing line separators. +*/ +EditorState.lineSeparator = lineSeparator; +/** +This facet controls the value of the +[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) getter, which is +consulted by commands and extensions that implement editing +functionality to determine whether they should apply. It +defaults to false, but when its highest-precedence value is +`true`, such functionality disables itself. + +Not to be confused with +[`EditorView.editable`](https://codemirror.net/6/docs/ref/#view.EditorView^editable), which +controls whether the editor's DOM is set to be editable (and +thus focusable). +*/ +EditorState.readOnly = readOnly; +/** +Registers translation phrases. The +[`phrase`](https://codemirror.net/6/docs/ref/#state.EditorState.phrase) method will look through +all objects registered with this facet to find translations for +its argument. +*/ +EditorState.phrases = Facet.define(); +/** +A facet used to register [language +data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) providers. +*/ +EditorState.languageData = languageData; +/** +Facet used to register change filters, which are called for each +transaction (unless explicitly +[disabled](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter)), and can suppress +part of the transaction's changes. + +Such a function can return `true` to indicate that it doesn't +want to do anything, `false` to completely stop the changes in +the transaction, or a set of ranges in which changes should be +suppressed. Such ranges are represented as an array of numbers, +with each pair of two number indicating the start and end of a +range. So for example `[10, 20, 100, 110]` suppresses changes +between 10 and 20, and between 100 and 110. +*/ +EditorState.changeFilter = changeFilter; +/** +Facet used to register a hook that gets a chance to update or +replace transaction specs before they are applied. This will +only be applied for transactions that don't have +[`filter`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter) set to `false`. You +can either return a single transaction spec (possibly the input +transaction), or an array of specs (which will be combined in +the same way as the arguments to +[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update)). + +When possible, it is recommended to avoid accessing +[`Transaction.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state) in a filter, +since it will force creation of a state that will then be +discarded again, if the transaction is actually filtered. + +(This functionality should be used with care. Indiscriminately +modifying transaction is likely to break something or degrade +the user experience.) +*/ +EditorState.transactionFilter = transactionFilter; +/** +This is a more limited form of +[`transactionFilter`](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter), +which can only add +[annotations](https://codemirror.net/6/docs/ref/#state.TransactionSpec.annotations) and +[effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects). _But_, this type +of filter runs even the transaction has disabled regular +[filtering](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter), making it suitable +for effects that don't need to touch the changes or selection, +but do want to process every transaction. + +Extenders run _after_ filters, when both are applied. +*/ +EditorState.transactionExtender = transactionExtender; +Compartment.reconfigure = StateEffect.define(); + +/** +Utility function for combining behaviors to fill in a config +object from an array of provided configs. Will, by default, error +when a field gets two values that aren't `===`-equal, but you can +provide combine functions per field to do something else. +*/ +function combineConfig(configs, defaults, // Should hold only the optional properties of Config, but I haven't managed to express that +combine = {}) { + let result = {}; + for (let config of configs) + for (let key of Object.keys(config)) { + let value = config[key], current = result[key]; + if (current === undefined) + result[key] = value; + else if (current === value || value === undefined) ; // No conflict + else if (Object.hasOwnProperty.call(combine, key)) + result[key] = combine[key](current, value); + else + throw new Error("Config merge conflict for field " + key); + } + for (let key in defaults) + if (result[key] === undefined) + result[key] = defaults[key]; + return result; +} + +Object.defineProperty(exports, 'Text', { + enumerable: true, + get: function () { + return text.Text; + } +}); +exports.Annotation = Annotation; +exports.AnnotationType = AnnotationType; +exports.ChangeDesc = ChangeDesc; +exports.ChangeSet = ChangeSet; +exports.Compartment = Compartment; +exports.EditorSelection = EditorSelection; +exports.EditorState = EditorState; +exports.Facet = Facet; +exports.Prec = Prec; +exports.SelectionRange = SelectionRange; +exports.StateEffect = StateEffect; +exports.StateEffectType = StateEffectType; +exports.StateField = StateField; +exports.Transaction = Transaction; +exports.combineConfig = combineConfig; + +},{"@codemirror/text":31}],31:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +// Compressed representation of the Grapheme_Cluster_Break=Extend +// information from +// http://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakProperty.txt. +// Each pair of elements represents a range, as an offet from the +// previous range and a length. Numbers are in base-36, with the empty +// string being a shorthand for 1. +let extend = "lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(s => s ? parseInt(s, 36) : 1); +// Convert offsets into absolute values +for (let i = 1; i < extend.length; i++) + extend[i] += extend[i - 1]; +function isExtendingChar(code) { + for (let i = 1; i < extend.length; i += 2) + if (extend[i] > code) + return extend[i - 1] <= code; + return false; +} +function isRegionalIndicator(code) { + return code >= 0x1F1E6 && code <= 0x1F1FF; +} +const ZWJ = 0x200d; +/** +Returns a next grapheme cluster break _after_ (not equal to) +`pos`, if `forward` is true, or before otherwise. Returns `pos` +itself if no further cluster break is available in the string. +Moves across surrogate pairs, extending characters (when +`includeExtending` is true), characters joined with zero-width +joiners, and flag emoji. +*/ +function findClusterBreak(str, pos, forward = true, includeExtending = true) { + return (forward ? nextClusterBreak : prevClusterBreak)(str, pos, includeExtending); +} +function nextClusterBreak(str, pos, includeExtending) { + if (pos == str.length) + return pos; + // If pos is in the middle of a surrogate pair, move to its start + if (pos && surrogateLow(str.charCodeAt(pos)) && surrogateHigh(str.charCodeAt(pos - 1))) + pos--; + let prev = codePointAt(str, pos); + pos += codePointSize(prev); + while (pos < str.length) { + let next = codePointAt(str, pos); + if (prev == ZWJ || next == ZWJ || includeExtending && isExtendingChar(next)) { + pos += codePointSize(next); + prev = next; + } + else if (isRegionalIndicator(next)) { + let countBefore = 0, i = pos - 2; + while (i >= 0 && isRegionalIndicator(codePointAt(str, i))) { + countBefore++; + i -= 2; } - if (cursor.to > to) + if (countBefore % 2 == 0) break; - pos = cursor.to; - cursor.next(); + else + pos += 2; + } + else { + break; } - return open; } - /** - Create a range set for the given range or array of ranges. By - default, this expects the ranges to be _sorted_ (by start - position and, if two start at the same position, - `value.startSide`). You can pass `true` as second argument to - cause the method to sort them. - */ - static of(ranges, sort = false) { - let build = new RangeSetBuilder(); - for (let range of ranges instanceof Range ? [ranges] : sort ? lazySort(ranges) : ranges) - build.add(range.from, range.to, range.value); - return build.finish(); + return pos; +} +function prevClusterBreak(str, pos, includeExtending) { + while (pos > 0) { + let found = nextClusterBreak(str, pos - 2, includeExtending); + if (found < pos) + return found; + pos--; } + return 0; } +function surrogateLow(ch) { return ch >= 0xDC00 && ch < 0xE000; } +function surrogateHigh(ch) { return ch >= 0xD800 && ch < 0xDC00; } /** -The empty set of ranges. +Find the code point at the given position in a string (like the +[`codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) +string method). */ -RangeSet.empty = new RangeSet([], [], null, -1); -function lazySort(ranges) { - if (ranges.length > 1) - for (let prev = ranges[0], i = 1; i < ranges.length; i++) { - let cur = ranges[i]; - if (cmpRange(prev, cur) > 0) - return ranges.slice().sort(cmpRange); - prev = cur; +function codePointAt(str, pos) { + let code0 = str.charCodeAt(pos); + if (!surrogateHigh(code0) || pos + 1 == str.length) + return code0; + let code1 = str.charCodeAt(pos + 1); + if (!surrogateLow(code1)) + return code0; + return ((code0 - 0xd800) << 10) + (code1 - 0xdc00) + 0x10000; +} +/** +Given a Unicode codepoint, return the JavaScript string that +respresents it (like +[`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint)). +*/ +function fromCodePoint(code) { + if (code <= 0xffff) + return String.fromCharCode(code); + code -= 0x10000; + return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00); +} +/** +The first character that takes up two positions in a JavaScript +string. It is often useful to compare with this after calling +`codePointAt`, to figure out whether your character takes up 1 or +2 index positions. +*/ +function codePointSize(code) { return code < 0x10000 ? 1 : 2; } + +/** +Count the column position at the given offset into the string, +taking extending characters and tab size into account. +*/ +function countColumn(string, tabSize, to = string.length) { + let n = 0; + for (let i = 0; i < to;) { + if (string.charCodeAt(i) == 9) { + n += tabSize - (n % tabSize); + i++; } - return ranges; + else { + n++; + i = findClusterBreak(string, i); + } + } + return n; } -RangeSet.empty.nextLayer = RangeSet.empty; /** -A range set builder is a data structure that helps build up a -[range set](https://codemirror.net/6/docs/ref/#rangeset.RangeSet) directly, without first allocating -an array of [`Range`](https://codemirror.net/6/docs/ref/#rangeset.Range) objects. +Find the offset that corresponds to the given column position in a +string, taking extending characters and tab size into account. By +default, the string length is returned when it is too short to +reach the column. Pass `strict` true to make it return -1 in that +situation. */ -class RangeSetBuilder { +function findColumn(string, col, tabSize, strict) { + for (let i = 0, n = 0;;) { + if (n >= col) + return i; + if (i == string.length) + break; + n += string.charCodeAt(i) == 9 ? tabSize - (n % tabSize) : 1; + i = findClusterBreak(string, i); + } + return strict === true ? -1 : string.length; +} + +/** +The data structure for documents. +*/ +class Text { + /** + @internal + */ + constructor() { } + /** + Get the line description around the given position. + */ + lineAt(pos) { + if (pos < 0 || pos > this.length) + throw new RangeError(`Invalid position ${pos} in document of length ${this.length}`); + return this.lineInner(pos, false, 1, 0); + } + /** + Get the description for the given (1-based) line number. + */ + line(n) { + if (n < 1 || n > this.lines) + throw new RangeError(`Invalid line number ${n} in ${this.lines}-line document`); + return this.lineInner(n, true, 1, 0); + } /** - Create an empty builder. + Replace a range of the text with the given content. */ - constructor() { - this.chunks = []; - this.chunkPos = []; - this.chunkStart = -1; - this.last = null; - this.lastFrom = -1000000000 /* Far */; - this.lastTo = -1000000000 /* Far */; - this.from = []; - this.to = []; - this.value = []; - this.maxPoint = -1; - this.setMaxPoint = -1; - this.nextLayer = null; - } - finishChunk(newArrays) { - this.chunks.push(new Chunk(this.from, this.to, this.value, this.maxPoint)); - this.chunkPos.push(this.chunkStart); - this.chunkStart = -1; - this.setMaxPoint = Math.max(this.setMaxPoint, this.maxPoint); - this.maxPoint = -1; - if (newArrays) { - this.from = []; - this.to = []; - this.value = []; - } + replace(from, to, text) { + let parts = []; + this.decompose(0, from, parts, 2 /* To */); + if (text.length) + text.decompose(0, text.length, parts, 1 /* From */ | 2 /* To */); + this.decompose(to, this.length, parts, 1 /* From */); + return TextNode.from(parts, this.length - (to - from) + text.length); } /** - Add a range. Ranges should be added in sorted (by `from` and - `value.startSide`) order. + Append another document to this one. */ - add(from, to, value) { - if (!this.addInner(from, to, value)) - (this.nextLayer || (this.nextLayer = new RangeSetBuilder)).add(from, to, value); + append(other) { + return this.replace(this.length, this.length, other); } /** - @internal + Retrieve the text between the given points. */ - addInner(from, to, value) { - let diff = from - this.lastTo || value.startSide - this.last.endSide; - if (diff <= 0 && (from - this.lastFrom || value.startSide - this.last.startSide) < 0) - throw new Error("Ranges must be added sorted by `from` position and `startSide`"); - if (diff < 0) - return false; - if (this.from.length == 250 /* ChunkSize */) - this.finishChunk(true); - if (this.chunkStart < 0) - this.chunkStart = from; - this.from.push(from - this.chunkStart); - this.to.push(to - this.chunkStart); - this.last = value; - this.lastFrom = from; - this.lastTo = to; - this.value.push(value); - if (value.point) - this.maxPoint = Math.max(this.maxPoint, to - from); - return true; + slice(from, to = this.length) { + let parts = []; + this.decompose(from, to, parts, 0); + return TextNode.from(parts, to - from); } /** - @internal + Test whether this text is equal to another instance. */ - addChunk(from, chunk) { - if ((from - this.lastTo || chunk.value[0].startSide - this.last.endSide) < 0) + eq(other) { + if (other == this) + return true; + if (other.length != this.length || other.lines != this.lines) return false; - if (this.from.length) - this.finishChunk(true); - this.setMaxPoint = Math.max(this.setMaxPoint, chunk.maxPoint); - this.chunks.push(chunk); - this.chunkPos.push(from); - let last = chunk.value.length - 1; - this.last = chunk.value[last]; - this.lastFrom = chunk.from[last] + from; - this.lastTo = chunk.to[last] + from; - return true; + let start = this.scanIdentical(other, 1), end = this.length - this.scanIdentical(other, -1); + let a = new RawTextCursor(this), b = new RawTextCursor(other); + for (let skip = start, pos = start;;) { + a.next(skip); + b.next(skip); + skip = 0; + if (a.lineBreak != b.lineBreak || a.done != b.done || a.value != b.value) + return false; + pos += a.value.length; + if (a.done || pos >= end) + return true; + } } /** - Finish the range set. Returns the new set. The builder can't be - used anymore after this has been called. + Iterate over the text. When `dir` is `-1`, iteration happens + from end to start. This will return lines and the breaks between + them as separate strings, and for long lines, might split lines + themselves into multiple chunks as well. */ - finish() { return this.finishInner(RangeSet.empty); } + iter(dir = 1) { return new RawTextCursor(this, dir); } + /** + Iterate over a range of the text. When `from` > `to`, the + iterator will run in reverse. + */ + iterRange(from, to = this.length) { return new PartialTextCursor(this, from, to); } + /** + Return a cursor that iterates over the given range of lines, + _without_ returning the line breaks between, and yielding empty + strings for empty lines. + + When `from` and `to` are given, they should be 1-based line numbers. + */ + iterLines(from, to) { + let inner; + if (from == null) { + inner = this.iter(); + } + else { + if (to == null) + to = this.lines + 1; + let start = this.line(from).from; + inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to)); + } + return new LineCursor(inner); + } /** @internal */ - finishInner(next) { - if (this.from.length) - this.finishChunk(false); - if (this.chunks.length == 0) - return next; - let result = new RangeSet(this.chunkPos, this.chunks, this.nextLayer ? this.nextLayer.finishInner(next) : next, this.setMaxPoint); - this.from = null; // Make sure further `add` calls produce errors - return result; + toString() { return this.sliceString(0); } + /** + Convert the document to an array of lines (which can be + deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#text.Text^of)). + */ + toJSON() { + let lines = []; + this.flatten(lines); + return lines; } -} -function findSharedChunks(a, b, textDiff) { - let inA = new Map(); - for (let set of a) - for (let i = 0; i < set.chunk.length; i++) - if (set.chunk[i].maxPoint <= 0) - inA.set(set.chunk[i], set.chunkPos[i]); - let shared = new Set(); - for (let set of b) - for (let i = 0; i < set.chunk.length; i++) { - let known = inA.get(set.chunk[i]); - if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set.chunkPos[i] && - !(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set.chunk[i].length))) - shared.add(set.chunk[i]); - } - return shared; -} -class LayerCursor { - constructor(layer, skip, minPoint, rank = 0) { - this.layer = layer; - this.skip = skip; - this.minPoint = minPoint; - this.rank = rank; + /** + Create a `Text` instance for the given array of lines. + */ + static of(text) { + if (text.length == 0) + throw new RangeError("A document must have at least one line"); + if (text.length == 1 && !text[0]) + return Text.empty; + return text.length <= 32 /* Branch */ ? new TextLeaf(text) : TextNode.from(TextLeaf.split(text, [])); } - get startSide() { return this.value ? this.value.startSide : 0; } - get endSide() { return this.value ? this.value.endSide : 0; } - goto(pos, side = -1000000000 /* Far */) { - this.chunkIndex = this.rangeIndex = 0; - this.gotoInner(pos, side, false); - return this; +} +// Leaves store an array of line strings. There are always line breaks +// between these strings. Leaves are limited in size and have to be +// contained in TextNode instances for bigger documents. +class TextLeaf extends Text { + constructor(text, length = textLength(text)) { + super(); + this.text = text; + this.length = length; } - gotoInner(pos, side, forward) { - while (this.chunkIndex < this.layer.chunk.length) { - let next = this.layer.chunk[this.chunkIndex]; - if (!(this.skip && this.skip.has(next) || - this.layer.chunkEnd(this.chunkIndex) < pos || - next.maxPoint < this.minPoint)) - break; - this.chunkIndex++; - forward = false; - } - if (this.chunkIndex < this.layer.chunk.length) { - let rangeIndex = this.layer.chunk[this.chunkIndex].findIndex(pos - this.layer.chunkPos[this.chunkIndex], side, true); - if (!forward || this.rangeIndex < rangeIndex) - this.setRangeIndex(rangeIndex); + get lines() { return this.text.length; } + get children() { return null; } + lineInner(target, isLine, line, offset) { + for (let i = 0;; i++) { + let string = this.text[i], end = offset + string.length; + if ((isLine ? line : end) >= target) + return new Line(offset, end, line, string); + offset = end + 1; + line++; } - this.next(); - } - forward(pos, side) { - if ((this.to - pos || this.endSide - side) < 0) - this.gotoInner(pos, side, true); } - next() { - for (;;) { - if (this.chunkIndex == this.layer.chunk.length) { - this.from = this.to = 1000000000 /* Far */; - this.value = null; - break; + decompose(from, to, target, open) { + let text = from <= 0 && to >= this.length ? this + : new TextLeaf(sliceText(this.text, from, to), Math.min(to, this.length) - Math.max(0, from)); + if (open & 1 /* From */) { + let prev = target.pop(); + let joined = appendText(text.text, prev.text.slice(), 0, text.length); + if (joined.length <= 32 /* Branch */) { + target.push(new TextLeaf(joined, prev.length + text.length)); } else { - let chunkPos = this.layer.chunkPos[this.chunkIndex], chunk = this.layer.chunk[this.chunkIndex]; - let from = chunkPos + chunk.from[this.rangeIndex]; - this.from = from; - this.to = chunkPos + chunk.to[this.rangeIndex]; - this.value = chunk.value[this.rangeIndex]; - this.setRangeIndex(this.rangeIndex + 1); - if (this.minPoint < 0 || this.value.point && this.to - this.from >= this.minPoint) - break; - } - } - } - setRangeIndex(index) { - if (index == this.layer.chunk[this.chunkIndex].value.length) { - this.chunkIndex++; - if (this.skip) { - while (this.chunkIndex < this.layer.chunk.length && this.skip.has(this.layer.chunk[this.chunkIndex])) - this.chunkIndex++; + let mid = joined.length >> 1; + target.push(new TextLeaf(joined.slice(0, mid)), new TextLeaf(joined.slice(mid))); } - this.rangeIndex = 0; } else { - this.rangeIndex = index; + target.push(text); } } - nextChunk() { - this.chunkIndex++; - this.rangeIndex = 0; - this.next(); + replace(from, to, text) { + if (!(text instanceof TextLeaf)) + return super.replace(from, to, text); + let lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to); + let newLen = this.length + text.length - (to - from); + if (lines.length <= 32 /* Branch */) + return new TextLeaf(lines, newLen); + return TextNode.from(TextLeaf.split(lines, []), newLen); } - compare(other) { - return this.from - other.from || this.startSide - other.startSide || this.to - other.to || this.endSide - other.endSide; + sliceString(from, to = this.length, lineSep = "\n") { + let result = ""; + for (let pos = 0, i = 0; pos <= to && i < this.text.length; i++) { + let line = this.text[i], end = pos + line.length; + if (pos > from && i) + result += lineSep; + if (from < end && to > pos) + result += line.slice(Math.max(0, from - pos), to - pos); + pos = end + 1; + } + return result; } -} -class HeapCursor { - constructor(heap) { - this.heap = heap; + flatten(target) { + for (let line of this.text) + target.push(line); } - static from(sets, skip = null, minPoint = -1) { - let heap = []; - for (let i = 0; i < sets.length; i++) { - for (let cur = sets[i]; !cur.isEmpty; cur = cur.nextLayer) { - if (cur.maxPoint >= minPoint) - heap.push(new LayerCursor(cur, skip, minPoint, i)); + scanIdentical() { return 0; } + static split(text, target) { + let part = [], len = -1; + for (let line of text) { + part.push(line); + len += line.length + 1; + if (part.length == 32 /* Branch */) { + target.push(new TextLeaf(part, len)); + part = []; + len = -1; } } - return heap.length == 1 ? heap[0] : new HeapCursor(heap); - } - get startSide() { return this.value ? this.value.startSide : 0; } - goto(pos, side = -1000000000 /* Far */) { - for (let cur of this.heap) - cur.goto(pos, side); - for (let i = this.heap.length >> 1; i >= 0; i--) - heapBubble(this.heap, i); - this.next(); - return this; + if (len > -1) + target.push(new TextLeaf(part, len)); + return target; } - forward(pos, side) { - for (let cur of this.heap) - cur.forward(pos, side); - for (let i = this.heap.length >> 1; i >= 0; i--) - heapBubble(this.heap, i); - if ((this.to - pos || this.value.endSide - side) < 0) - this.next(); +} +// Nodes provide the tree structure of the `Text` type. They store a +// number of other nodes or leaves, taking care to balance themselves +// on changes. There are implied line breaks _between_ the children of +// a node (but not before the first or after the last child). +class TextNode extends Text { + constructor(children, length) { + super(); + this.children = children; + this.length = length; + this.lines = 0; + for (let child of children) + this.lines += child.lines; } - next() { - if (this.heap.length == 0) { - this.from = this.to = 1000000000 /* Far */; - this.value = null; - this.rank = -1; + lineInner(target, isLine, line, offset) { + for (let i = 0;; i++) { + let child = this.children[i], end = offset + child.length, endLine = line + child.lines - 1; + if ((isLine ? endLine : end) >= target) + return child.lineInner(target, isLine, line, offset); + offset = end + 1; + line = endLine + 1; } - else { - let top = this.heap[0]; - this.from = top.from; - this.to = top.to; - this.value = top.value; - this.rank = top.rank; - if (top.value) - top.next(); - heapBubble(this.heap, 0); + } + decompose(from, to, target, open) { + for (let i = 0, pos = 0; pos <= to && i < this.children.length; i++) { + let child = this.children[i], end = pos + child.length; + if (from <= end && to >= pos) { + let childOpen = open & ((pos <= from ? 1 /* From */ : 0) | (end >= to ? 2 /* To */ : 0)); + if (pos >= from && end <= to && !childOpen) + target.push(child); + else + child.decompose(from - pos, to - pos, target, childOpen); + } + pos = end + 1; } } -} -function heapBubble(heap, index) { - for (let cur = heap[index];;) { - let childIndex = (index << 1) + 1; - if (childIndex >= heap.length) - break; - let child = heap[childIndex]; - if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) { - child = heap[childIndex + 1]; - childIndex++; + replace(from, to, text) { + if (text.lines < this.lines) + for (let i = 0, pos = 0; i < this.children.length; i++) { + let child = this.children[i], end = pos + child.length; + // Fast path: if the change only affects one child and the + // child's size remains in the acceptable range, only update + // that child + if (from >= pos && to <= end) { + let updated = child.replace(from - pos, to - pos, text); + let totalLines = this.lines - child.lines + updated.lines; + if (updated.lines < (totalLines >> (5 /* BranchShift */ - 1)) && + updated.lines > (totalLines >> (5 /* BranchShift */ + 1))) { + let copy = this.children.slice(); + copy[i] = updated; + return new TextNode(copy, this.length - (to - from) + text.length); + } + return super.replace(pos, end, updated); + } + pos = end + 1; + } + return super.replace(from, to, text); + } + sliceString(from, to = this.length, lineSep = "\n") { + let result = ""; + for (let i = 0, pos = 0; i < this.children.length && pos <= to; i++) { + let child = this.children[i], end = pos + child.length; + if (pos > from && i) + result += lineSep; + if (from < end && to > pos) + result += child.sliceString(from - pos, to - pos, lineSep); + pos = end + 1; } - if (cur.compare(child) < 0) - break; - heap[childIndex] = cur; - heap[index] = child; - index = childIndex; + return result; } -} -class SpanCursor { - constructor(sets, skip, minPoint, filterPoint = () => true) { - this.minPoint = minPoint; - this.filterPoint = filterPoint; - this.active = []; - this.activeTo = []; - this.activeRank = []; - this.minActive = -1; - // A currently active point range, if any - this.point = null; - this.pointFrom = 0; - this.pointRank = 0; - this.to = -1000000000 /* Far */; - this.endSide = 0; - this.openStart = -1; - this.cursor = HeapCursor.from(sets, skip, minPoint); + flatten(target) { + for (let child of this.children) + child.flatten(target); } - goto(pos, side = -1000000000 /* Far */) { - this.cursor.goto(pos, side); - this.active.length = this.activeTo.length = this.activeRank.length = 0; - this.minActive = -1; - this.to = pos; - this.endSide = side; - this.openStart = -1; - this.next(); - return this; + scanIdentical(other, dir) { + if (!(other instanceof TextNode)) + return 0; + let length = 0; + let [iA, iB, eA, eB] = dir > 0 ? [0, 0, this.children.length, other.children.length] + : [this.children.length - 1, other.children.length - 1, -1, -1]; + for (;; iA += dir, iB += dir) { + if (iA == eA || iB == eB) + return length; + let chA = this.children[iA], chB = other.children[iB]; + if (chA != chB) + return length + chA.scanIdentical(chB, dir); + length += chA.length + 1; + } } - forward(pos, side) { - while (this.minActive > -1 && (this.activeTo[this.minActive] - pos || this.active[this.minActive].endSide - side) < 0) - this.removeActive(this.minActive); - this.cursor.forward(pos, side); + static from(children, length = children.reduce((l, ch) => l + ch.length + 1, -1)) { + let lines = 0; + for (let ch of children) + lines += ch.lines; + if (lines < 32 /* Branch */) { + let flat = []; + for (let ch of children) + ch.flatten(flat); + return new TextLeaf(flat, length); + } + let chunk = Math.max(32 /* Branch */, lines >> 5 /* BranchShift */), maxChunk = chunk << 1, minChunk = chunk >> 1; + let chunked = [], currentLines = 0, currentLen = -1, currentChunk = []; + function add(child) { + let last; + if (child.lines > maxChunk && child instanceof TextNode) { + for (let node of child.children) + add(node); + } + else if (child.lines > minChunk && (currentLines > minChunk || !currentLines)) { + flush(); + chunked.push(child); + } + else if (child instanceof TextLeaf && currentLines && + (last = currentChunk[currentChunk.length - 1]) instanceof TextLeaf && + child.lines + last.lines <= 32 /* Branch */) { + currentLines += child.lines; + currentLen += child.length + 1; + currentChunk[currentChunk.length - 1] = new TextLeaf(last.text.concat(child.text), last.length + 1 + child.length); + } + else { + if (currentLines + child.lines > chunk) + flush(); + currentLines += child.lines; + currentLen += child.length + 1; + currentChunk.push(child); + } + } + function flush() { + if (currentLines == 0) + return; + chunked.push(currentChunk.length == 1 ? currentChunk[0] : TextNode.from(currentChunk, currentLen)); + currentLen = -1; + currentLines = currentChunk.length = 0; + } + for (let child of children) + add(child); + flush(); + return chunked.length == 1 ? chunked[0] : new TextNode(chunked, length); } - removeActive(index) { - remove(this.active, index); - remove(this.activeTo, index); - remove(this.activeRank, index); - this.minActive = findMinIndex(this.active, this.activeTo); +} +Text.empty = new TextLeaf([""], 0); +function textLength(text) { + let length = -1; + for (let line of text) + length += line.length + 1; + return length; +} +function appendText(text, target, from = 0, to = 1e9) { + for (let pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) { + let line = text[i], end = pos + line.length; + if (end >= from) { + if (end > to) + line = line.slice(0, to - pos); + if (pos < from) + line = line.slice(from - pos); + if (first) { + target[target.length - 1] += line; + first = false; + } + else + target.push(line); + } + pos = end + 1; } - addActive(trackOpen) { - let i = 0, { value, to, rank } = this.cursor; - while (i < this.activeRank.length && this.activeRank[i] <= rank) - i++; - insert(this.active, i, value); - insert(this.activeTo, i, to); - insert(this.activeRank, i, rank); - if (trackOpen) - insert(trackOpen, i, this.cursor.from); - this.minActive = findMinIndex(this.active, this.activeTo); + return target; +} +function sliceText(text, from, to) { + return appendText(text, [""], from, to); +} +class RawTextCursor { + constructor(text, dir = 1) { + this.dir = dir; + this.done = false; + this.lineBreak = false; + this.value = ""; + this.nodes = [text]; + this.offsets = [dir > 0 ? 1 : (text instanceof TextLeaf ? text.text.length : text.children.length) << 1]; } - // After calling this, if `this.point` != null, the next range is a - // point. Otherwise, it's a regular range, covered by `this.active`. - next() { - let from = this.to, wasPoint = this.point; - this.point = null; - let trackOpen = this.openStart < 0 ? [] : null, trackExtra = 0; + nextInner(skip, dir) { + this.done = this.lineBreak = false; for (;;) { - let a = this.minActive; - if (a > -1 && (this.activeTo[a] - this.cursor.from || this.active[a].endSide - this.cursor.startSide) < 0) { - if (this.activeTo[a] > from) { - this.to = this.activeTo[a]; - this.endSide = this.active[a].endSide; - break; + let last = this.nodes.length - 1; + let top = this.nodes[last], offsetValue = this.offsets[last], offset = offsetValue >> 1; + let size = top instanceof TextLeaf ? top.text.length : top.children.length; + if (offset == (dir > 0 ? size : 0)) { + if (last == 0) { + this.done = true; + this.value = ""; + return this; } - this.removeActive(a); - if (trackOpen) - remove(trackOpen, a); + if (dir > 0) + this.offsets[last - 1]++; + this.nodes.pop(); + this.offsets.pop(); } - else if (!this.cursor.value) { - this.to = this.endSide = 1000000000 /* Far */; - break; + else if ((offsetValue & 1) == (dir > 0 ? 0 : 1)) { + this.offsets[last] += dir; + if (skip == 0) { + this.lineBreak = true; + this.value = "\n"; + return this; + } + skip--; } - else if (this.cursor.from > from) { - this.to = this.cursor.from; - this.endSide = this.cursor.startSide; - break; + else if (top instanceof TextLeaf) { + // Move to the next string + let next = top.text[offset + (dir < 0 ? -1 : 0)]; + this.offsets[last] += dir; + if (next.length > Math.max(0, skip)) { + this.value = skip == 0 ? next : dir > 0 ? next.slice(skip) : next.slice(0, next.length - skip); + return this; + } + skip -= next.length; } else { - let nextVal = this.cursor.value; - if (!nextVal.point) { // Opening a range - this.addActive(trackOpen); - this.cursor.next(); - } - else if (wasPoint && this.cursor.to == this.to && this.cursor.from < this.cursor.to) { - // Ignore any non-empty points that end precisely at the end of the prev point - this.cursor.next(); - } - else if (!this.filterPoint(this.cursor.from, this.cursor.to, this.cursor.value, this.cursor.rank)) { - this.cursor.next(); + let next = top.children[offset + (dir < 0 ? -1 : 0)]; + if (skip > next.length) { + skip -= next.length; + this.offsets[last] += dir; } - else { // New point - this.point = nextVal; - this.pointFrom = this.cursor.from; - this.pointRank = this.cursor.rank; - this.to = this.cursor.to; - this.endSide = nextVal.endSide; - if (this.cursor.from < from) - trackExtra = 1; - this.cursor.next(); - if (this.to > from) - this.forward(this.to, this.endSide); - break; + else { + if (dir < 0) + this.offsets[last]--; + this.nodes.push(next); + this.offsets.push(dir > 0 ? 1 : (next instanceof TextLeaf ? next.text.length : next.children.length) << 1); } } } - if (trackOpen) { - let openStart = 0; - while (openStart < trackOpen.length && trackOpen[openStart] < from) - openStart++; - this.openStart = openStart + trackExtra; + } + next(skip = 0) { + if (skip < 0) { + this.nextInner(-skip, (-this.dir)); + skip = this.value.length; } + return this.nextInner(skip, this.dir); } - activeForPoint(to) { - if (!this.active.length) - return this.active; - let active = []; - for (let i = this.active.length - 1; i >= 0; i--) { - if (this.activeRank[i] < this.pointRank) - break; - if (this.activeTo[i] > to || this.activeTo[i] == to && this.active[i].endSide >= this.point.endSide) - active.push(this.active[i]); +} +class PartialTextCursor { + constructor(text, start, end) { + this.value = ""; + this.done = false; + this.cursor = new RawTextCursor(text, start > end ? -1 : 1); + this.pos = start > end ? text.length : 0; + this.from = Math.min(start, end); + this.to = Math.max(start, end); + } + nextInner(skip, dir) { + if (dir < 0 ? this.pos <= this.from : this.pos >= this.to) { + this.value = ""; + this.done = true; + return this; } - return active.reverse(); + skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos); + let limit = dir < 0 ? this.pos - this.from : this.to - this.pos; + if (skip > limit) + skip = limit; + limit -= skip; + let { value } = this.cursor.next(skip); + this.pos += (value.length + skip) * dir; + this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit); + this.done = !this.value; + return this; } - openEnd(to) { - let open = 0; - for (let i = this.activeTo.length - 1; i >= 0 && this.activeTo[i] > to; i--) - open++; - return open; + next(skip = 0) { + if (skip < 0) + skip = Math.max(skip, this.from - this.pos); + else if (skip > 0) + skip = Math.min(skip, this.to - this.pos); + return this.nextInner(skip, this.cursor.dir); } + get lineBreak() { return this.cursor.lineBreak && this.value != ""; } } -function compare(a, startA, b, startB, length, comparator) { - a.goto(startA); - b.goto(startB); - let endB = startB + length; - let pos = startB, dPos = startB - startA; - for (;;) { - let diff = (a.to + dPos) - b.to || a.endSide - b.endSide; - let end = diff < 0 ? a.to + dPos : b.to, clipEnd = Math.min(end, endB); - if (a.point || b.point) { - if (!(a.point && b.point && (a.point == b.point || a.point.eq(b.point)) && - sameValues(a.activeForPoint(a.to + dPos), b.activeForPoint(b.to)))) - comparator.comparePoint(pos, clipEnd, a.point, b.point); +class LineCursor { + constructor(inner) { + this.inner = inner; + this.afterBreak = true; + this.value = ""; + this.done = false; + } + next(skip = 0) { + let { done, lineBreak, value } = this.inner.next(skip); + if (done) { + this.done = true; + this.value = ""; + } + else if (lineBreak) { + if (this.afterBreak) { + this.value = ""; + } + else { + this.afterBreak = true; + this.next(); + } } else { - if (clipEnd > pos && !sameValues(a.active, b.active)) - comparator.compareRange(pos, clipEnd, a.active, b.active); + this.value = value; + this.afterBreak = false; } - if (end > endB) - break; - pos = end; - if (diff <= 0) - a.next(); - if (diff >= 0) - b.next(); + return this; } + get lineBreak() { return false; } } -function sameValues(a, b) { - if (a.length != b.length) - return false; - for (let i = 0; i < a.length; i++) - if (a[i] != b[i] && !a[i].eq(b[i])) - return false; - return true; -} -function remove(array, index) { - for (let i = index, e = array.length - 1; i < e; i++) - array[i] = array[i + 1]; - array.pop(); -} -function insert(array, index, value) { - for (let i = array.length - 1; i >= index; i--) - array[i + 1] = array[i]; - array[index] = value; -} -function findMinIndex(value, array) { - let found = -1, foundPos = 1000000000 /* Far */; - for (let i = 0; i < array.length; i++) - if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) { - found = i; - foundPos = array[i]; - } - return found; +if (typeof Symbol != "undefined") { + Text.prototype[Symbol.iterator] = function () { return this.iter(); }; + RawTextCursor.prototype[Symbol.iterator] = PartialTextCursor.prototype[Symbol.iterator] = + LineCursor.prototype[Symbol.iterator] = function () { return this; }; } - -exports.Range = Range; -exports.RangeSet = RangeSet; -exports.RangeSetBuilder = RangeSetBuilder; -exports.RangeValue = RangeValue; - -},{"@codemirror/state":51}],51:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var text = require('@codemirror/text'); - -const DefaultSplit = /\r\n?|\n/; /** -Distinguishes different ways in which positions can be mapped. +This type describes a line in the document. It is created +on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#text.Text.lineAt). */ -exports.MapMode = void 0; -(function (MapMode) { - /** - Map a position to a valid new position, even when its context - was deleted. - */ - MapMode[MapMode["Simple"] = 0] = "Simple"; +class Line { /** - Return null if deletion happens across the position. + @internal */ - MapMode[MapMode["TrackDel"] = 1] = "TrackDel"; + constructor( /** - Return null if the character _before_ the position is deleted. + The position of the start of the line. */ - MapMode[MapMode["TrackBefore"] = 2] = "TrackBefore"; + from, /** - Return null if the character _after_ the position is deleted. + The position at the end of the line (_before_ the line break, + or at the end of document for the last line). */ - MapMode[MapMode["TrackAfter"] = 3] = "TrackAfter"; -})(exports.MapMode || (exports.MapMode = {})); -/** -A change description is a variant of [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) -that doesn't store the inserted text. As such, it can't be -applied, but is cheaper to store and manipulate. -*/ -class ChangeDesc { - // Sections are encoded as pairs of integers. The first is the - // length in the current document, and the second is -1 for - // unaffected sections, and the length of the replacement content - // otherwise. So an insertion would be (0, n>0), a deletion (n>0, - // 0), and a replacement two positive numbers. + to, /** - @internal + This line's line number (1-based). */ - constructor( + number, /** - @internal + The line's content. */ - sections) { - this.sections = sections; + text) { + this.from = from; + this.to = to; + this.number = number; + this.text = text; } /** - The length of the document before the change. + The length of the line (not including any line break after it). */ - get length() { - let result = 0; - for (let i = 0; i < this.sections.length; i += 2) - result += this.sections[i]; - return result; + get length() { return this.to - this.from; } +} + +exports.Line = Line; +exports.Text = Text; +exports.codePointAt = codePointAt; +exports.codePointSize = codePointSize; +exports.countColumn = countColumn; +exports.findClusterBreak = findClusterBreak; +exports.findColumn = findColumn; +exports.fromCodePoint = fromCodePoint; + +},{}],32:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var view = require('@codemirror/view'); +var state = require('@codemirror/state'); + +const ios = typeof navigator != "undefined" && + !/Edge\/(\d+)/.exec(navigator.userAgent) && /Apple Computer/.test(navigator.vendor) && + (/Mobile\/\w+/.test(navigator.userAgent) || navigator.maxTouchPoints > 2); +const Outside = "-10000px"; +class TooltipViewManager { + constructor(view, facet, createTooltipView) { + this.facet = facet; + this.createTooltipView = createTooltipView; + this.input = view.state.facet(facet); + this.tooltips = this.input.filter(t => t); + this.tooltipViews = this.tooltips.map(createTooltipView); } - /** - The length of the document after the change. - */ - get newLength() { - let result = 0; - for (let i = 0; i < this.sections.length; i += 2) { - let ins = this.sections[i + 1]; - result += ins < 0 ? this.sections[i] : ins; + update(update) { + let input = update.state.facet(this.facet); + let tooltips = input.filter(x => x); + if (input === this.input) { + for (let t of this.tooltipViews) + if (t.update) + t.update(update); + return false; + } + let tooltipViews = []; + for (let i = 0; i < tooltips.length; i++) { + let tip = tooltips[i], known = -1; + if (!tip) + continue; + for (let i = 0; i < this.tooltips.length; i++) { + let other = this.tooltips[i]; + if (other && other.create == tip.create) + known = i; + } + if (known < 0) { + tooltipViews[i] = this.createTooltipView(tip); + } + else { + let tooltipView = tooltipViews[i] = this.tooltipViews[known]; + if (tooltipView.update) + tooltipView.update(update); + } + } + for (let t of this.tooltipViews) + if (tooltipViews.indexOf(t) < 0) + t.dom.remove(); + this.input = input; + this.tooltips = tooltips; + this.tooltipViews = tooltipViews; + return true; + } +} +/** +Return an extension that configures tooltip behavior. +*/ +function tooltips(config = {}) { + return tooltipConfig.of(config); +} +function windowSpace() { + return { top: 0, left: 0, bottom: innerHeight, right: innerWidth }; +} +const tooltipConfig = state.Facet.define({ + combine: values => { + var _a, _b, _c; + return ({ + position: ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed", + parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null, + tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace, + }); + } +}); +const tooltipPlugin = view.ViewPlugin.fromClass(class { + constructor(view) { + var _a; + this.view = view; + this.inView = true; + this.lastTransaction = 0; + this.measureTimeout = -1; + let config = view.state.facet(tooltipConfig); + this.position = config.position; + this.parent = config.parent; + this.classes = view.themeClasses; + this.createContainer(); + this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this }; + this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t)); + this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => { + if (Date.now() > this.lastTransaction - 50 && + entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1) + this.measureSoon(); + }, { threshold: [1] }) : null; + this.observeIntersection(); + (_a = view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this)); + this.maybeMeasure(); + } + createContainer() { + if (this.parent) { + this.container = document.createElement("div"); + this.container.style.position = "relative"; + this.container.className = this.view.themeClasses; + this.parent.appendChild(this.container); + } + else { + this.container = this.view.dom; + } + } + observeIntersection() { + if (this.intersectionObserver) { + this.intersectionObserver.disconnect(); + for (let tooltip of this.manager.tooltipViews) + this.intersectionObserver.observe(tooltip.dom); + } + } + measureSoon() { + if (this.measureTimeout < 0) + this.measureTimeout = setTimeout(() => { + this.measureTimeout = -1; + this.maybeMeasure(); + }, 50); + } + update(update) { + if (update.transactions.length) + this.lastTransaction = Date.now(); + let updated = this.manager.update(update); + if (updated) + this.observeIntersection(); + let shouldMeasure = updated || update.geometryChanged; + let newConfig = update.state.facet(tooltipConfig); + if (newConfig.position != this.position) { + this.position = newConfig.position; + for (let t of this.manager.tooltipViews) + t.dom.style.position = this.position; + shouldMeasure = true; + } + if (newConfig.parent != this.parent) { + if (this.parent) + this.container.remove(); + this.parent = newConfig.parent; + this.createContainer(); + for (let t of this.manager.tooltipViews) + this.container.appendChild(t.dom); + shouldMeasure = true; + } + else if (this.parent && this.view.themeClasses != this.classes) { + this.classes = this.container.className = this.view.themeClasses; } - return result; + if (shouldMeasure) + this.maybeMeasure(); } - /** - False when there are actual changes in this set. - */ - get empty() { return this.sections.length == 0 || this.sections.length == 2 && this.sections[1] < 0; } - /** - Iterate over the unchanged parts left by these changes. - */ - iterGaps(f) { - for (let i = 0, posA = 0, posB = 0; i < this.sections.length;) { - let len = this.sections[i++], ins = this.sections[i++]; - if (ins < 0) { - f(posA, posB, len); - posB += len; - } - else { - posB += ins; - } - posA += len; + createTooltip(tooltip) { + let tooltipView = tooltip.create(this.view); + tooltipView.dom.classList.add("cm-tooltip"); + if (tooltip.arrow && !tooltipView.dom.querySelector("cm-tooltip > cm-tooltip-arrow")) { + let arrow = document.createElement("div"); + arrow.className = "cm-tooltip-arrow"; + tooltipView.dom.appendChild(arrow); } + tooltipView.dom.style.position = this.position; + tooltipView.dom.style.top = Outside; + this.container.appendChild(tooltipView.dom); + if (tooltipView.mount) + tooltipView.mount(this.view); + return tooltipView; } - /** - Iterate over the ranges changed by these changes. (See - [`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a - variant that also provides you with the inserted text.) - - When `individual` is true, adjacent changes (which are kept - separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are - reported separately. - */ - iterChangedRanges(f, individual = false) { - iterChanges(this, f, individual); + destroy() { + var _a, _b; + (_a = this.view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener("resize", this.measureSoon); + for (let { dom } of this.manager.tooltipViews) + dom.remove(); + (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect(); + clearTimeout(this.measureTimeout); } - /** - Get a description of the inverted form of these changes. - */ - get invertedDesc() { - let sections = []; - for (let i = 0; i < this.sections.length;) { - let len = this.sections[i++], ins = this.sections[i++]; - if (ins < 0) - sections.push(len, ins); - else - sections.push(ins, len); - } - return new ChangeDesc(sections); + readMeasure() { + let editor = this.view.dom.getBoundingClientRect(); + return { + editor, + parent: this.parent ? this.container.getBoundingClientRect() : editor, + pos: this.manager.tooltips.map(t => this.view.coordsAtPos(t.pos)), + size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()), + space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view), + }; } - /** - Compute the combined effect of applying another set of changes - after this one. The length of the document after this set should - match the length before `other`. - */ - composeDesc(other) { return this.empty ? other : other.empty ? this : composeSets(this, other); } - /** - Map this description, which should start with the same document - as `other`, over another set of changes, so that it can be - applied after it. When `before` is true, map as if the changes - in `other` happened before the ones in `this`. - */ - mapDesc(other, before = false) { return other.empty ? this : mapSet(this, other, before); } - mapPos(pos, assoc = -1, mode = exports.MapMode.Simple) { - let posA = 0, posB = 0; - for (let i = 0; i < this.sections.length;) { - let len = this.sections[i++], ins = this.sections[i++], endA = posA + len; - if (ins < 0) { - if (endA > pos) - return posB + (pos - posA); - posB += len; + writeMeasure(measured) { + let { editor, space } = measured; + let others = []; + for (let i = 0; i < this.manager.tooltips.length; i++) { + let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView; + let pos = measured.pos[i], size = measured.size[i]; + // Hide tooltips that are outside of the editor. + if (!pos || pos.bottom <= Math.max(editor.top, space.top) || + pos.top >= Math.min(editor.bottom, space.bottom) || + pos.right <= Math.max(editor.left, space.left) || + pos.left >= Math.min(editor.right, space.right)) { + dom.style.top = Outside; + continue; + } + let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null; + let arrowHeight = arrow ? 7 /* Size */ : 0; + let width = size.right - size.left, height = size.bottom - size.top; + let offset = tView.offset || noOffset, ltr = this.view.textDirection == view.Direction.LTR; + let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width) + : ltr ? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0) + offset.x, space.right - width) + : Math.max(space.left, pos.left - width + (arrow ? 14 /* Offset */ : 0) - offset.x); + let above = !!tooltip.above; + if (!tooltip.strictSide && (above + ? pos.top - (size.bottom - size.top) - offset.y < space.top + : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) && + above == (space.bottom - pos.bottom > pos.top - space.top)) + above = !above; + let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y; + let right = left + width; + for (let r of others) + if (r.left < right && r.right > left && r.top < top + height && r.bottom > top) + top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2; + if (this.position == "absolute") { + dom.style.top = (top - measured.parent.top) + "px"; + dom.style.left = (left - measured.parent.left) + "px"; } else { - if (mode != exports.MapMode.Simple && endA >= pos && - (mode == exports.MapMode.TrackDel && posA < pos && endA > pos || - mode == exports.MapMode.TrackBefore && posA < pos || - mode == exports.MapMode.TrackAfter && endA > pos)) - return null; - if (endA > pos || endA == pos && assoc < 0 && !len) - return pos == posA || assoc < 0 ? posB : posB + ins; - posB += ins; + dom.style.top = top + "px"; + dom.style.left = left + "px"; } - posA = endA; + if (arrow) + arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Offset */ - 7 /* Size */)}px`; + others.push({ left, top, right, bottom: top + height }); + dom.classList.toggle("cm-tooltip-above", above); + dom.classList.toggle("cm-tooltip-below", !above); + if (tView.positioned) + tView.positioned(); } - if (pos > posA) - throw new RangeError(`Position ${pos} is out of range for changeset of length ${posA}`); - return posB; } - /** - Check whether these changes touch a given range. When one of the - changes entirely covers the range, the string `"cover"` is - returned. - */ - touchesRange(from, to = from) { - for (let i = 0, pos = 0; i < this.sections.length && pos <= to;) { - let len = this.sections[i++], ins = this.sections[i++], end = pos + len; - if (ins >= 0 && pos <= to && end >= from) - return pos < from && end > to ? "cover" : true; - pos = end; + maybeMeasure() { + if (this.manager.tooltips.length) { + if (this.view.inView) + this.view.requestMeasure(this.measureReq); + if (this.inView != this.view.inView) { + this.inView = this.view.inView; + if (!this.inView) + for (let tv of this.manager.tooltipViews) + tv.dom.style.top = Outside; + } } - return false; } - /** - @internal - */ - toString() { - let result = ""; - for (let i = 0; i < this.sections.length;) { - let len = this.sections[i++], ins = this.sections[i++]; - result += (result ? " " : "") + len + (ins >= 0 ? ":" + ins : ""); - } - return result; +}, { + eventHandlers: { + scroll() { this.maybeMeasure(); } } - /** - Serialize this change desc to a JSON-representable value. - */ - toJSON() { return this.sections; } - /** - Create a change desc from its JSON representation (as produced - by [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeDesc.toJSON). - */ - static fromJSON(json) { - if (!Array.isArray(json) || json.length % 2 || json.some(a => typeof a != "number")) - throw new RangeError("Invalid JSON representation of ChangeDesc"); - return new ChangeDesc(json); +}); +const baseTheme = view.EditorView.baseTheme({ + ".cm-tooltip": { + zIndex: 100 + }, + "&light .cm-tooltip": { + border: "1px solid #bbb", + backgroundColor: "#f5f5f5" + }, + "&light .cm-tooltip-section:not(:first-child)": { + borderTop: "1px solid #bbb", + }, + "&dark .cm-tooltip": { + backgroundColor: "#333338", + color: "white" + }, + ".cm-tooltip-arrow": { + height: `${7 /* Size */}px`, + width: `${7 /* Size */ * 2}px`, + position: "absolute", + zIndex: -1, + overflow: "hidden", + "&:before, &:after": { + content: "''", + position: "absolute", + width: 0, + height: 0, + borderLeft: `${7 /* Size */}px solid transparent`, + borderRight: `${7 /* Size */}px solid transparent`, + }, + ".cm-tooltip-above &": { + bottom: `-${7 /* Size */}px`, + "&:before": { + borderTop: `${7 /* Size */}px solid #bbb`, + }, + "&:after": { + borderTop: `${7 /* Size */}px solid #f5f5f5`, + bottom: "1px" + } + }, + ".cm-tooltip-below &": { + top: `-${7 /* Size */}px`, + "&:before": { + borderBottom: `${7 /* Size */}px solid #bbb`, + }, + "&:after": { + borderBottom: `${7 /* Size */}px solid #f5f5f5`, + top: "1px" + } + }, + }, + "&dark .cm-tooltip .cm-tooltip-arrow": { + "&:before": { + borderTopColor: "#333338", + borderBottomColor: "#333338" + }, + "&:after": { + borderTopColor: "transparent", + borderBottomColor: "transparent" + } } -} +}); +const noOffset = { x: 0, y: 0 }; /** -A change set represents a group of modifications to a document. It -stores the document length, and can only be applied to documents -with exactly that length. +Behavior by which an extension can provide a tooltip to be shown. */ -class ChangeSet extends ChangeDesc { - /** - @internal - */ - constructor(sections, - /** - @internal - */ - inserted) { - super(sections); - this.inserted = inserted; - } - /** - Apply the changes to a document, returning the modified - document. - */ - apply(doc) { - if (this.length != doc.length) - throw new RangeError("Applying change set to a document with the wrong length"); - iterChanges(this, (fromA, toA, fromB, _toB, text) => doc = doc.replace(fromB, fromB + (toA - fromA), text), false); - return doc; +const showTooltip = state.Facet.define({ + enables: [tooltipPlugin, baseTheme] +}); +const showHoverTooltip = state.Facet.define(); +class HoverTooltipHost { + constructor(view) { + this.view = view; + this.mounted = false; + this.dom = document.createElement("div"); + this.dom.classList.add("cm-tooltip-hover"); + this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t)); } - mapDesc(other, before = false) { return mapSet(this, other, before, true); } - /** - Given the document as it existed _before_ the changes, return a - change set that represents the inverse of this set, which could - be used to go from the document created by the changes back to - the document as it existed before the changes. - */ - invert(doc) { - let sections = this.sections.slice(), inserted = []; - for (let i = 0, pos = 0; i < sections.length; i += 2) { - let len = sections[i], ins = sections[i + 1]; - if (ins >= 0) { - sections[i] = ins; - sections[i + 1] = len; - let index = i >> 1; - while (inserted.length < index) - inserted.push(text.Text.empty); - inserted.push(len ? doc.slice(pos, pos + len) : text.Text.empty); - } - pos += len; - } - return new ChangeSet(sections, inserted); + // Needs to be static so that host tooltip instances always match + static create(view) { + return new HoverTooltipHost(view); } - /** - Combine two subsequent change sets into a single set. `other` - must start in the document produced by `this`. If `this` goes - `docA` → `docB` and `other` represents `docB` → `docC`, the - returned value will represent the change `docA` → `docC`. - */ - compose(other) { return this.empty ? other : other.empty ? this : composeSets(this, other, true); } - /** - Given another change set starting in the same document, maps this - change set over the other, producing a new change set that can be - applied to the document produced by applying `other`. When - `before` is `true`, order changes as if `this` comes before - `other`, otherwise (the default) treat `other` as coming first. - - Given two changes `A` and `B`, `A.compose(B.map(A))` and - `B.compose(A.map(B, true))` will produce the same document. This - provides a basic form of [operational - transformation](https://en.wikipedia.org/wiki/Operational_transformation), - and can be used for collaborative editing. - */ - map(other, before = false) { return other.empty ? this : mapSet(this, other, before, true); } - /** - Iterate over the changed ranges in the document, calling `f` for - each. - - When `individual` is true, adjacent changes are reported - separately. - */ - iterChanges(f, individual = false) { - iterChanges(this, f, individual); + createHostedView(tooltip) { + let hostedView = tooltip.create(this.view); + hostedView.dom.classList.add("cm-tooltip-section"); + this.dom.appendChild(hostedView.dom); + if (this.mounted && hostedView.mount) + hostedView.mount(this.view); + return hostedView; } - /** - Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change - set. - */ - get desc() { return new ChangeDesc(this.sections); } - /** - @internal - */ - filter(ranges) { - let resultSections = [], resultInserted = [], filteredSections = []; - let iter = new SectionIter(this); - done: for (let i = 0, pos = 0;;) { - let next = i == ranges.length ? 1e9 : ranges[i++]; - while (pos < next || pos == next && iter.len == 0) { - if (iter.done) - break done; - let len = Math.min(iter.len, next - pos); - addSection(filteredSections, len, -1); - let ins = iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0; - addSection(resultSections, len, ins); - if (ins > 0) - addInsert(resultInserted, resultSections, iter.text); - iter.forward(len); - pos += len; - } - let end = ranges[i++]; - while (pos < end) { - if (iter.done) - break done; - let len = Math.min(iter.len, end - pos); - addSection(resultSections, len, -1); - addSection(filteredSections, len, iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0); - iter.forward(len); - pos += len; - } + mount(view) { + for (let hostedView of this.manager.tooltipViews) { + if (hostedView.mount) + hostedView.mount(view); } - return { changes: new ChangeSet(resultSections, resultInserted), - filtered: new ChangeDesc(filteredSections) }; + this.mounted = true; } - /** - Serialize this change set to a JSON-representable value. - */ - toJSON() { - let parts = []; - for (let i = 0; i < this.sections.length; i += 2) { - let len = this.sections[i], ins = this.sections[i + 1]; - if (ins < 0) - parts.push(len); - else if (ins == 0) - parts.push([len]); - else - parts.push([len].concat(this.inserted[i >> 1].toJSON())); + positioned() { + for (let hostedView of this.manager.tooltipViews) { + if (hostedView.positioned) + hostedView.positioned(); } - return parts; } - /** - Create a change set for the given changes, for a document of the - given length, using `lineSep` as line separator. - */ - static of(changes, length, lineSep) { - let sections = [], inserted = [], pos = 0; - let total = null; - function flush(force = false) { - if (!force && !sections.length) - return; - if (pos < length) - addSection(sections, length - pos, -1); - let set = new ChangeSet(sections, inserted); - total = total ? total.compose(set.map(total)) : set; - sections = []; - inserted = []; - pos = 0; + update(update) { + this.manager.update(update); + } +} +const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => { + let tooltips = state.facet(showHoverTooltip).filter(t => t); + if (tooltips.length === 0) + return null; + return { + pos: Math.min(...tooltips.map(t => t.pos)), + end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)), + create: HoverTooltipHost.create, + above: tooltips[0].above, + arrow: tooltips.some(t => t.arrow), + }; +}); +class HoverPlugin { + constructor(view, source, field, setHover, hoverTime) { + this.view = view; + this.source = source; + this.field = field; + this.setHover = setHover; + this.hoverTime = hoverTime; + this.hoverTimeout = -1; + this.restartTimeout = -1; + this.pending = null; + this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 }; + this.checkHover = this.checkHover.bind(this); + view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this)); + view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this)); + } + update() { + if (this.pending) { + this.pending = null; + clearTimeout(this.restartTimeout); + this.restartTimeout = setTimeout(() => this.startHover(), 20); } - function process(spec) { - if (Array.isArray(spec)) { - for (let sub of spec) - process(sub); - } - else if (spec instanceof ChangeSet) { - if (spec.length != length) - throw new RangeError(`Mismatched change set length (got ${spec.length}, expected ${length})`); - flush(); - total = total ? total.compose(spec.map(total)) : spec; - } - else { - let { from, to = from, insert } = spec; - if (from > to || from < 0 || to > length) - throw new RangeError(`Invalid change range ${from} to ${to} (in doc of length ${length})`); - let insText = !insert ? text.Text.empty : typeof insert == "string" ? text.Text.of(insert.split(lineSep || DefaultSplit)) : insert; - let insLen = insText.length; - if (from == to && insLen == 0) - return; - if (from < pos) - flush(); - if (from > pos) - addSection(sections, from - pos, -1); - addSection(sections, to - from, insLen); - addInsert(inserted, sections, insText); - pos = to; + } + get active() { + return this.view.state.field(this.field); + } + checkHover() { + this.hoverTimeout = -1; + if (this.active) + return; + let hovered = Date.now() - this.lastMove.time; + if (hovered < this.hoverTime) + this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered); + else + this.startHover(); + } + startHover() { + var _a; + clearTimeout(this.restartTimeout); + let { lastMove } = this; + let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null; + if (pos == null) + return; + let posCoords = this.view.coordsAtPos(pos); + if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom || + lastMove.x < posCoords.left - this.view.defaultCharacterWidth || + lastMove.x > posCoords.right + this.view.defaultCharacterWidth) + return; + let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos); + let rtl = bidi && bidi.dir == view.Direction.RTL ? -1 : 1; + let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl)); + if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) { + let pending = this.pending = { pos }; + open.then(result => { + if (this.pending == pending) { + this.pending = null; + if (result) + this.view.dispatch({ effects: this.setHover.of(result) }); + } + }, e => view.logException(this.view.state, e, "hover tooltip")); + } + else if (open) { + this.view.dispatch({ effects: this.setHover.of(open) }); + } + } + mousemove(event) { + var _a; + this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() }; + if (this.hoverTimeout < 0) + this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime); + let tooltip = this.active; + if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) { + let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos; + if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos + : !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) { + this.view.dispatch({ effects: this.setHover.of(null) }); + this.pending = null; } } - process(changes); - flush(!total); - return total; } - /** - Create an empty changeset of the given length. - */ - static empty(length) { - return new ChangeSet(length ? [length, -1] : [], []); + mouseleave() { + clearTimeout(this.hoverTimeout); + this.hoverTimeout = -1; + if (this.active) + this.view.dispatch({ effects: this.setHover.of(null) }); } - /** - Create a changeset from its JSON representation (as produced by - [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeSet.toJSON). - */ - static fromJSON(json) { - if (!Array.isArray(json)) - throw new RangeError("Invalid JSON representation of ChangeSet"); - let sections = [], inserted = []; - for (let i = 0; i < json.length; i++) { - let part = json[i]; - if (typeof part == "number") { - sections.push(part, -1); - } - else if (!Array.isArray(part) || typeof part[0] != "number" || part.some((e, i) => i && typeof e != "string")) { - throw new RangeError("Invalid JSON representation of ChangeSet"); - } - else if (part.length == 1) { - sections.push(part[0], 0); + destroy() { + clearTimeout(this.hoverTimeout); + this.view.dom.removeEventListener("mouseleave", this.mouseleave); + this.view.dom.removeEventListener("mousemove", this.mousemove); + } +} +function isInTooltip(elt) { + for (let cur = elt; cur; cur = cur.parentNode) + if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip")) + return true; + return false; +} +function isOverRange(view, from, to, x, y, margin) { + let range = document.createRange(); + let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to); + range.setEnd(toDOM.node, toDOM.offset); + range.setStart(fromDOM.node, fromDOM.offset); + let rects = range.getClientRects(); + range.detach(); + for (let i = 0; i < rects.length; i++) { + let rect = rects[i]; + let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right); + if (dist <= margin) + return true; + } + return false; +} +/** +Enable a hover tooltip, which shows up when the pointer hovers +over ranges of text. The callback is called when the mouse hovers +over the document text. It should, if there is a tooltip +associated with position `pos` return the tooltip description +(either directly or in a promise). The `side` argument indicates +on which side of the position the pointer is—it will be -1 if the +pointer is before the position, 1 if after the position. + +Note that all hover tooltips are hosted within a single tooltip +container element. This allows multiple tooltips over the same +range to be "merged" together without overlapping. +*/ +function hoverTooltip(source, options = {}) { + let setHover = state.StateEffect.define(); + let hoverState = state.StateField.define({ + create() { return null; }, + update(value, tr) { + if (value && (options.hideOnChange && (tr.docChanged || tr.selection))) + return null; + for (let effect of tr.effects) { + if (effect.is(setHover)) + return effect.value; + if (effect.is(closeHoverTooltipEffect)) + return null; } - else { - while (inserted.length < i) - inserted.push(text.Text.empty); - inserted[i] = text.Text.of(part.slice(1)); - sections.push(part[0], inserted[i].length); + if (value && tr.docChanged) { + let newPos = tr.changes.mapPos(value.pos, -1, state.MapMode.TrackDel); + if (newPos == null) + return null; + let copy = Object.assign(Object.create(null), value); + copy.pos = newPos; + if (value.end != null) + copy.end = tr.changes.mapPos(value.end); + return copy; } - } - return new ChangeSet(sections, inserted); + return value; + }, + provide: f => showHoverTooltip.from(f) + }); + let hoverTime = options.hoverTime || 600 /* Time */; + return [ + hoverState, + view.ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, hoverTime)), + showHoverTooltipHost + ]; +} +/** +Get the active tooltip view for a given tooltip, if available. +*/ +function getTooltip(view, tooltip) { + let plugin = view.plugin(tooltipPlugin); + if (!plugin) + return null; + let found = plugin.manager.tooltips.indexOf(tooltip); + return found < 0 ? null : plugin.manager.tooltipViews[found]; +} +/** +Returns true if any hover tooltips are currently active. +*/ +function hasHoverTooltips(state) { + return state.facet(showHoverTooltip).some(x => x); +} +const closeHoverTooltipEffect = state.StateEffect.define(); +/** +Transaction effect that closes all hover tooltips. +*/ +const closeHoverTooltips = closeHoverTooltipEffect.of(null); +/** +Tell the tooltip extension to recompute the position of the active +tooltips. This can be useful when something happens (such as a +re-positioning or CSS change affecting the editor) that could +invalidate the existing tooltip positions. +*/ +function repositionTooltips(view) { + var _a; + (_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure(); +} + +exports.closeHoverTooltips = closeHoverTooltips; +exports.getTooltip = getTooltip; +exports.hasHoverTooltips = hasHoverTooltips; +exports.hoverTooltip = hoverTooltip; +exports.repositionTooltips = repositionTooltips; +exports.showTooltip = showTooltip; +exports.tooltips = tooltips; + +},{"@codemirror/state":30,"@codemirror/view":33}],33:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var state = require('@codemirror/state'); +var styleMod = require('style-mod'); +var rangeset = require('@codemirror/rangeset'); +var text = require('@codemirror/text'); +var w3cKeyname = require('w3c-keyname'); + +function getSelection(root) { + let target; + // Browsers differ on whether shadow roots have a getSelection + // method. If it exists, use that, otherwise, call it on the + // document. + if (root.nodeType == 11) { // Shadow root + target = root.getSelection ? root : root.ownerDocument; + } + else { + target = root; } + return target.getSelection(); } -function addSection(sections, len, ins, forceJoin = false) { - if (len == 0 && ins <= 0) - return; - let last = sections.length - 2; - if (last >= 0 && ins <= 0 && ins == sections[last + 1]) - sections[last] += len; - else if (len == 0 && sections[last] == 0) - sections[last + 1] += ins; - else if (forceJoin) { - sections[last] += len; - sections[last + 1] += ins; +function contains(dom, node) { + return node ? dom.contains(node.nodeType != 1 ? node.parentNode : node) : false; +} +function deepActiveElement() { + let elt = document.activeElement; + while (elt && elt.shadowRoot) + elt = elt.shadowRoot.activeElement; + return elt; +} +function hasSelection(dom, selection) { + if (!selection.anchorNode) + return false; + try { + // Firefox will raise 'permission denied' errors when accessing + // properties of `sel.anchorNode` when it's in a generated CSS + // element. + return contains(dom, selection.anchorNode); + } + catch (_) { + return false; } +} +function clientRectsFor(dom) { + if (dom.nodeType == 3) + return textRange(dom, 0, dom.nodeValue.length).getClientRects(); + else if (dom.nodeType == 1) + return dom.getClientRects(); else - sections.push(len, ins); + return []; } -function addInsert(values, sections, value) { - if (value.length == 0) - return; - let index = (sections.length - 2) >> 1; - if (index < values.length) { - values[values.length - 1] = values[values.length - 1].append(value); - } - else { - while (values.length < index) - values.push(text.Text.empty); - values.push(value); +// Scans forward and backward through DOM positions equivalent to the +// given one to see if the two are in the same place (i.e. after a +// text node vs at the end of that text node) +function isEquivalentPosition(node, off, targetNode, targetOff) { + return targetNode ? (scanFor(node, off, targetNode, targetOff, -1) || + scanFor(node, off, targetNode, targetOff, 1)) : false; +} +function domIndex(node) { + for (var index = 0;; index++) { + node = node.previousSibling; + if (!node) + return index; } } -function iterChanges(desc, f, individual) { - let inserted = desc.inserted; - for (let posA = 0, posB = 0, i = 0; i < desc.sections.length;) { - let len = desc.sections[i++], ins = desc.sections[i++]; - if (ins < 0) { - posA += len; - posB += len; +function scanFor(node, off, targetNode, targetOff, dir) { + for (;;) { + if (node == targetNode && off == targetOff) + return true; + if (off == (dir < 0 ? 0 : maxOffset(node))) { + if (node.nodeName == "DIV") + return false; + let parent = node.parentNode; + if (!parent || parent.nodeType != 1) + return false; + off = domIndex(node) + (dir < 0 ? 0 : 1); + node = parent; + } + else if (node.nodeType == 1) { + node = node.childNodes[off + (dir < 0 ? -1 : 0)]; + if (node.nodeType == 1 && node.contentEditable == "false") + return false; + off = dir < 0 ? maxOffset(node) : 0; } else { - let endA = posA, endB = posB, text$1 = text.Text.empty; - for (;;) { - endA += len; - endB += ins; - if (ins && inserted) - text$1 = text$1.append(inserted[(i - 2) >> 1]); - if (individual || i == desc.sections.length || desc.sections[i + 1] < 0) - break; - len = desc.sections[i++]; - ins = desc.sections[i++]; - } - f(posA, endA, posB, endB, text$1); - posA = endA; - posB = endB; + return false; } } } -function mapSet(setA, setB, before, mkSet = false) { - let sections = [], insert = mkSet ? [] : null; - let a = new SectionIter(setA), b = new SectionIter(setB); - for (let posA = 0, posB = 0;;) { - if (a.ins == -1) { - posA += a.len; - a.next(); - } - else if (b.ins == -1 && posB < posA) { - let skip = Math.min(b.len, posA - posB); - b.forward(skip); - addSection(sections, skip, -1); - posB += skip; - } - else if (b.ins >= 0 && (a.done || posB < posA || posB == posA && (b.len < a.len || b.len == a.len && !before))) { - addSection(sections, b.ins, -1); - while (posA > posB && !a.done && posA + a.len < posB + b.len) { - posA += a.len; - a.next(); +function maxOffset(node) { + return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length; +} +const Rect0 = { left: 0, right: 0, top: 0, bottom: 0 }; +function flattenRect(rect, left) { + let x = left ? rect.left : rect.right; + return { left: x, right: x, top: rect.top, bottom: rect.bottom }; +} +function windowRect(win) { + return { left: 0, right: win.innerWidth, + top: 0, bottom: win.innerHeight }; +} +function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) { + let doc = dom.ownerDocument, win = doc.defaultView; + for (let cur = dom; cur;) { + if (cur.nodeType == 1) { // Element + let bounding, top = cur == doc.body; + if (top) { + bounding = windowRect(win); } - posB += b.len; - b.next(); - } - else if (a.ins >= 0) { - let len = 0, end = posA + a.len; - for (;;) { - if (b.ins >= 0 && posB > posA && posB + b.len < end) { - len += b.ins; - posB += b.len; - b.next(); + else { + if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) { + cur = cur.parentNode; + continue; } - else if (b.ins == -1 && posB < end) { - let skip = Math.min(b.len, end - posB); - len += skip; - b.forward(skip); - posB += skip; + let rect = cur.getBoundingClientRect(); + // Make sure scrollbar width isn't included in the rectangle + bounding = { left: rect.left, right: rect.left + cur.clientWidth, + top: rect.top, bottom: rect.top + cur.clientHeight }; + } + let moveX = 0, moveY = 0; + if (y == "nearest") { + if (rect.top < bounding.top) { + moveY = -(bounding.top - rect.top + yMargin); + if (side > 0 && rect.bottom > bounding.bottom + moveY) + moveY = rect.bottom - bounding.bottom + moveY + yMargin; } - else { - break; + else if (rect.bottom > bounding.bottom) { + moveY = rect.bottom - bounding.bottom + yMargin; + if (side < 0 && (rect.top - moveY) < bounding.top) + moveY = -(bounding.top + moveY - rect.top + yMargin); } } - addSection(sections, len, a.ins); - if (insert) - addInsert(insert, sections, a.text); - posA = end; - a.next(); - } - else if (a.done && b.done) { - return insert ? new ChangeSet(sections, insert) : new ChangeDesc(sections); - } - else { - throw new Error("Mismatched change set lengths"); - } - } -} -function composeSets(setA, setB, mkSet = false) { - let sections = []; - let insert = mkSet ? [] : null; - let a = new SectionIter(setA), b = new SectionIter(setB); - for (let open = false;;) { - if (a.done && b.done) { - return insert ? new ChangeSet(sections, insert) : new ChangeDesc(sections); - } - else if (a.ins == 0) { // Deletion in A - addSection(sections, a.len, 0, open); - a.next(); - } - else if (b.len == 0 && !b.done) { // Insertion in B - addSection(sections, 0, b.ins, open); - if (insert) - addInsert(insert, sections, b.text); - b.next(); - } - else if (a.done || b.done) { - throw new Error("Mismatched change set lengths"); - } - else { - let len = Math.min(a.len2, b.len), sectionLen = sections.length; - if (a.ins == -1) { - let insB = b.ins == -1 ? -1 : b.off ? 0 : b.ins; - addSection(sections, len, insB, open); - if (insert && insB) - addInsert(insert, sections, b.text); + else { + let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top; + let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 : + y == "start" || y == "center" && side < 0 ? rect.top - yMargin : + rect.bottom - boundingHeight + yMargin; + moveY = targetTop - bounding.top; } - else if (b.ins == -1) { - addSection(sections, a.off ? 0 : a.len, len, open); - if (insert) - addInsert(insert, sections, a.textBit(len)); + if (x == "nearest") { + if (rect.left < bounding.left) { + moveX = -(bounding.left - rect.left + xMargin); + if (side > 0 && rect.right > bounding.right + moveX) + moveX = rect.right - bounding.right + moveX + xMargin; + } + else if (rect.right > bounding.right) { + moveX = rect.right - bounding.right + xMargin; + if (side < 0 && rect.left < bounding.left + moveX) + moveX = -(bounding.left + moveX - rect.left + xMargin); + } } else { - addSection(sections, a.off ? 0 : a.len, b.off ? 0 : b.ins, open); - if (insert && !b.off) - addInsert(insert, sections, b.text); + let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 : + (x == "start") == ltr ? rect.left - xMargin : + rect.right - (bounding.right - bounding.left) + xMargin; + moveX = targetLeft - bounding.left; } - open = (a.ins > len || b.ins >= 0 && b.len > len) && (open || sections.length > sectionLen); - a.forward2(len); - b.forward(len); - } - } -} -class SectionIter { - constructor(set) { - this.set = set; - this.i = 0; - this.next(); - } - next() { - let { sections } = this.set; - if (this.i < sections.length) { - this.len = sections[this.i++]; - this.ins = sections[this.i++]; - } - else { - this.len = 0; - this.ins = -2; - } - this.off = 0; - } - get done() { return this.ins == -2; } - get len2() { return this.ins < 0 ? this.len : this.ins; } - get text() { - let { inserted } = this.set, index = (this.i - 2) >> 1; - return index >= inserted.length ? text.Text.empty : inserted[index]; - } - textBit(len) { - let { inserted } = this.set, index = (this.i - 2) >> 1; - return index >= inserted.length && !len ? text.Text.empty - : inserted[index].slice(this.off, len == null ? undefined : this.off + len); - } - forward(len) { - if (len == this.len) - this.next(); - else { - this.len -= len; - this.off += len; + if (moveX || moveY) { + if (top) { + win.scrollBy(moveX, moveY); + } + else { + if (moveY) { + let start = cur.scrollTop; + cur.scrollTop += moveY; + moveY = cur.scrollTop - start; + } + if (moveX) { + let start = cur.scrollLeft; + cur.scrollLeft += moveX; + moveX = cur.scrollLeft - start; + } + rect = { left: rect.left - moveX, top: rect.top - moveY, + right: rect.right - moveX, bottom: rect.bottom - moveY }; + } + } + if (top) + break; + cur = cur.assignedSlot || cur.parentNode; + x = y = "nearest"; + } + else if (cur.nodeType == 11) { // A shadow root + cur = cur.host; } - } - forward2(len) { - if (this.ins == -1) - this.forward(len); - else if (len == this.ins) - this.next(); else { - this.ins -= len; - this.off += len; + break; } } } - -/** -A single selection range. When -[`allowMultipleSelections`](https://codemirror.net/6/docs/ref/#state.EditorState^allowMultipleSelections) -is enabled, a [selection](https://codemirror.net/6/docs/ref/#state.EditorSelection) may hold -multiple ranges. By default, selections hold exactly one range. -*/ -class SelectionRange { - /** - @internal - */ - constructor( - /** - The lower boundary of the range. - */ - from, - /** - The upper boundary of the range. - */ - to, flags) { - this.from = from; - this.to = to; - this.flags = flags; - } - /** - The anchor of the range—the side that doesn't move when you - extend it. - */ - get anchor() { return this.flags & 16 /* Inverted */ ? this.to : this.from; } - /** - The head of the range, which is moved when the range is - [extended](https://codemirror.net/6/docs/ref/#state.SelectionRange.extend). - */ - get head() { return this.flags & 16 /* Inverted */ ? this.from : this.to; } - /** - True when `anchor` and `head` are at the same position. - */ - get empty() { return this.from == this.to; } - /** - If this is a cursor that is explicitly associated with the - character on one of its sides, this returns the side. -1 means - the character before its position, 1 the character after, and 0 - means no association. - */ - get assoc() { return this.flags & 4 /* AssocBefore */ ? -1 : this.flags & 8 /* AssocAfter */ ? 1 : 0; } - /** - The bidirectional text level associated with this cursor, if - any. - */ - get bidiLevel() { - let level = this.flags & 3 /* BidiLevelMask */; - return level == 3 ? null : level; - } - /** - The goal column (stored vertical offset) associated with a - cursor. This is used to preserve the vertical position when - [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across - lines of different length. - */ - get goalColumn() { - let value = this.flags >> 5 /* GoalColumnOffset */; - return value == 33554431 /* NoGoalColumn */ ? undefined : value; - } - /** - Map this range through a change, producing a valid range in the - updated document. - */ - map(change, assoc = -1) { - let from = change.mapPos(this.from, assoc), to = change.mapPos(this.to, assoc); - return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags); +class DOMSelectionState { + constructor() { + this.anchorNode = null; + this.anchorOffset = 0; + this.focusNode = null; + this.focusOffset = 0; } - /** - Extend this range to cover at least `from` to `to`. - */ - extend(from, to = from) { - if (from <= this.anchor && to >= this.anchor) - return EditorSelection.range(from, to); - let head = Math.abs(from - this.anchor) > Math.abs(to - this.anchor) ? from : to; - return EditorSelection.range(this.anchor, head); + eq(domSel) { + return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset && + this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset; } - /** - Compare this range to another range. - */ - eq(other) { - return this.anchor == other.anchor && this.head == other.head; + setRange(range) { + this.set(range.anchorNode, range.anchorOffset, range.focusNode, range.focusOffset); } - /** - Return a JSON-serializable object representing the range. - */ - toJSON() { return { anchor: this.anchor, head: this.head }; } - /** - Convert a JSON representation of a range to a `SelectionRange` - instance. - */ - static fromJSON(json) { - if (!json || typeof json.anchor != "number" || typeof json.head != "number") - throw new RangeError("Invalid JSON representation for SelectionRange"); - return EditorSelection.range(json.anchor, json.head); + set(anchorNode, anchorOffset, focusNode, focusOffset) { + this.anchorNode = anchorNode; + this.anchorOffset = anchorOffset; + this.focusNode = focusNode; + this.focusOffset = focusOffset; } } -/** -An editor selection holds one or more selection ranges. -*/ -class EditorSelection { - /** - @internal - */ - constructor( - /** - The ranges in the selection, sorted by position. Ranges cannot - overlap (but they may touch, if they aren't empty). - */ - ranges, - /** - The index of the _main_ range in the selection (which is - usually the range that was added last). - */ - mainIndex = 0) { - this.ranges = ranges; - this.mainIndex = mainIndex; - } - /** - Map a selection through a change. Used to adjust the selection - position for changes. - */ - map(change, assoc = -1) { - if (change.empty) - return this; - return EditorSelection.create(this.ranges.map(r => r.map(change, assoc)), this.mainIndex); - } - /** - Compare this selection to another selection. - */ - eq(other) { - if (this.ranges.length != other.ranges.length || - this.mainIndex != other.mainIndex) - return false; - for (let i = 0; i < this.ranges.length; i++) - if (!this.ranges[i].eq(other.ranges[i])) - return false; - return true; - } - /** - Get the primary selection range. Usually, you should make sure - your code applies to _all_ ranges, by using methods like - [`changeByRange`](https://codemirror.net/6/docs/ref/#state.EditorState.changeByRange). - */ - get main() { return this.ranges[this.mainIndex]; } - /** - Make sure the selection only has one range. Returns a selection - holding only the main range from this selection. - */ - asSingle() { - return this.ranges.length == 1 ? this : new EditorSelection([this.main]); - } - /** - Extend this selection with an extra range. - */ - addRange(range, main = true) { - return EditorSelection.create([range].concat(this.ranges), main ? 0 : this.mainIndex + 1); - } - /** - Replace a given range with another range, and then normalize the - selection to merge and sort ranges if necessary. - */ - replaceRange(range, which = this.mainIndex) { - let ranges = this.ranges.slice(); - ranges[which] = range; - return EditorSelection.create(ranges, this.mainIndex); - } - /** - Convert this selection to an object that can be serialized to - JSON. - */ - toJSON() { - return { ranges: this.ranges.map(r => r.toJSON()), main: this.mainIndex }; - } - /** - Create a selection from a JSON representation. - */ - static fromJSON(json) { - if (!json || !Array.isArray(json.ranges) || typeof json.main != "number" || json.main >= json.ranges.length) - throw new RangeError("Invalid JSON representation for EditorSelection"); - return new EditorSelection(json.ranges.map((r) => SelectionRange.fromJSON(r)), json.main); - } - /** - Create a selection holding a single range. - */ - static single(anchor, head = anchor) { - return new EditorSelection([EditorSelection.range(anchor, head)], 0); +let preventScrollSupported = null; +// Feature-detects support for .focus({preventScroll: true}), and uses +// a fallback kludge when not supported. +function focusPreventScroll(dom) { + if (dom.setActive) + return dom.setActive(); // in IE + if (preventScrollSupported) + return dom.focus(preventScrollSupported); + let stack = []; + for (let cur = dom; cur; cur = cur.parentNode) { + stack.push(cur, cur.scrollTop, cur.scrollLeft); + if (cur == cur.ownerDocument) + break; } - /** - Sort and merge the given set of ranges, creating a valid - selection. - */ - static create(ranges, mainIndex = 0) { - if (ranges.length == 0) - throw new RangeError("A selection needs at least one range"); - for (let pos = 0, i = 0; i < ranges.length; i++) { - let range = ranges[i]; - if (range.empty ? range.from <= pos : range.from < pos) - return normalized(ranges.slice(), mainIndex); - pos = range.to; + dom.focus(preventScrollSupported == null ? { + get preventScroll() { + preventScrollSupported = { preventScroll: true }; + return true; + } + } : undefined); + if (!preventScrollSupported) { + preventScrollSupported = false; + for (let i = 0; i < stack.length;) { + let elt = stack[i++], top = stack[i++], left = stack[i++]; + if (elt.scrollTop != top) + elt.scrollTop = top; + if (elt.scrollLeft != left) + elt.scrollLeft = left; } - return new EditorSelection(ranges, mainIndex); - } - /** - Create a cursor selection range at the given position. You can - safely ignore the optional arguments in most situations. - */ - static cursor(pos, assoc = 0, bidiLevel, goalColumn) { - return new SelectionRange(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 4 /* AssocBefore */ : 8 /* AssocAfter */) | - (bidiLevel == null ? 3 : Math.min(2, bidiLevel)) | - ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* NoGoalColumn */) << 5 /* GoalColumnOffset */)); - } - /** - Create a selection range. - */ - static range(anchor, head, goalColumn) { - let goal = (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* NoGoalColumn */) << 5 /* GoalColumnOffset */; - return head < anchor ? new SelectionRange(head, anchor, 16 /* Inverted */ | goal) : new SelectionRange(anchor, head, goal); } } -function normalized(ranges, mainIndex = 0) { - let main = ranges[mainIndex]; - ranges.sort((a, b) => a.from - b.from); - mainIndex = ranges.indexOf(main); - for (let i = 1; i < ranges.length; i++) { - let range = ranges[i], prev = ranges[i - 1]; - if (range.empty ? range.from <= prev.to : range.from < prev.to) { - let from = prev.from, to = Math.max(range.to, prev.to); - if (i <= mainIndex) - mainIndex--; - ranges.splice(--i, 2, range.anchor > range.head ? EditorSelection.range(to, from) : EditorSelection.range(from, to)); - } +let scratchRange; +function textRange(node, from, to = from) { + let range = scratchRange || (scratchRange = document.createRange()); + range.setEnd(node, to); + range.setStart(node, from); + return range; +} +function dispatchKey(elt, name, code) { + let options = { key: name, code: name, keyCode: code, which: code, cancelable: true }; + let down = new KeyboardEvent("keydown", options); + down.synthetic = true; + elt.dispatchEvent(down); + let up = new KeyboardEvent("keyup", options); + up.synthetic = true; + elt.dispatchEvent(up); + return down.defaultPrevented || up.defaultPrevented; +} +function getRoot(node) { + while (node) { + if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host)) + return node; + node = node.assignedSlot || node.parentNode; } - return new EditorSelection(ranges, mainIndex); + return null; } -function checkSelection(selection, docLength) { - for (let range of selection.ranges) - if (range.to > docLength) - throw new RangeError("Selection points outside of document"); +function clearAttributes(node) { + while (node.attributes.length) + node.removeAttributeNode(node.attributes[0]); } -let nextID = 0; -/** -A facet is a labeled value that is associated with an editor -state. It takes inputs from any number of extensions, and combines -those into a single output value. - -Examples of facets are the [theme](https://codemirror.net/6/docs/ref/#view.EditorView^theme) styles -associated with an editor or the [tab -size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) (which is reduced to a single -value, using the input with the hightest precedence). -*/ -class Facet { - constructor( - /** - @internal - */ - combine, - /** - @internal - */ - compareInput, - /** - @internal - */ - compare, isStatic, - /** - @internal - */ - extensions) { - this.combine = combine; - this.compareInput = compareInput; - this.compare = compare; - this.isStatic = isStatic; - this.extensions = extensions; - /** - @internal - */ - this.id = nextID++; - this.default = combine([]); +class DOMPos { + constructor(node, offset, precise = true) { + this.node = node; + this.offset = offset; + this.precise = precise; } - /** - Define a new facet. - */ - static define(config = {}) { - return new Facet(config.combine || ((a) => a), config.compareInput || ((a, b) => a === b), config.compare || (!config.combine ? sameArray : (a, b) => a === b), !!config.static, config.enables); + static before(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); } + static after(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); } +} +const noChildren = []; +class ContentView { + constructor() { + this.parent = null; + this.dom = null; + this.dirty = 2 /* Node */; } - /** - Returns an extension that adds the given value for this facet. - */ - of(value) { - return new FacetProvider([], this, 0 /* Static */, value); + get editorView() { + if (!this.parent) + throw new Error("Accessing view in orphan content view"); + return this.parent.editorView; } - /** - Create an extension that computes a value for the facet from a - state. You must take care to declare the parts of the state that - this value depends on, since your function is only called again - for a new state when one of those parts changed. - - In most cases, you'll want to use the - [`provide`](https://codemirror.net/6/docs/ref/#state.StateField^define^config.provide) option when - defining a field instead. - */ - compute(deps, get) { - if (this.isStatic) - throw new Error("Can't compute a static facet"); - return new FacetProvider(deps, this, 1 /* Single */, get); + get overrideDOMText() { return null; } + get posAtStart() { + return this.parent ? this.parent.posBefore(this) : 0; } - /** - Create an extension that computes zero or more values for this - facet from a state. - */ - computeN(deps, get) { - if (this.isStatic) - throw new Error("Can't compute a static facet"); - return new FacetProvider(deps, this, 2 /* Multi */, get); + get posAtEnd() { + return this.posAtStart + this.length; } - from(field, get) { - if (!get) - get = x => x; - return this.compute([field], state => get(state.field(field))); + posBefore(view) { + let pos = this.posAtStart; + for (let child of this.children) { + if (child == view) + return pos; + pos += child.length + child.breakAfter; + } + throw new RangeError("Invalid child in posBefore"); } -} -function sameArray(a, b) { - return a == b || a.length == b.length && a.every((e, i) => e === b[i]); -} -class FacetProvider { - constructor(dependencies, facet, type, value) { - this.dependencies = dependencies; - this.facet = facet; - this.type = type; - this.value = value; - this.id = nextID++; + posAfter(view) { + return this.posBefore(view) + view.length; } - dynamicSlot(addresses) { - var _a; - let getter = this.value; - let compare = this.facet.compareInput; - let idx = addresses[this.id] >> 1, multi = this.type == 2 /* Multi */; - let depDoc = false, depSel = false, depAddrs = []; - for (let dep of this.dependencies) { - if (dep == "doc") - depDoc = true; - else if (dep == "selection") - depSel = true; - else if ((((_a = addresses[dep.id]) !== null && _a !== void 0 ? _a : 1) & 1) == 0) - depAddrs.push(addresses[dep.id]); - } - return (state, tr) => { - let oldVal = state.values[idx]; - if (oldVal === Uninitialized) { - state.values[idx] = getter(state); - return 1 /* Changed */; - } - if (tr) { - let depChanged = (depDoc && tr.docChanged) || (depSel && (tr.docChanged || tr.selection)) || - depAddrs.some(addr => (ensureAddr(state, addr) & 1 /* Changed */) > 0); - if (depChanged) { - let newVal = getter(state); - if (multi ? !compareArray(newVal, oldVal, compare) : !compare(newVal, oldVal)) { - state.values[idx] = newVal; - return 1 /* Changed */; + // Will return a rectangle directly before (when side < 0), after + // (side > 0) or directly on (when the browser supports it) the + // given position. + coordsAt(_pos, _side) { return null; } + sync(track) { + if (this.dirty & 2 /* Node */) { + let parent = this.dom; + let pos = parent.firstChild; + for (let child of this.children) { + if (child.dirty) { + if (!child.dom && pos) { + let contentView = ContentView.get(pos); + if (!contentView || !contentView.parent && contentView.constructor == child.constructor) + child.reuseDOM(pos); } + child.sync(track); + child.dirty = 0 /* Not */; + } + if (track && !track.written && track.node == parent && pos != child.dom) + track.written = true; + if (child.dom.parentNode == parent) { + while (pos && pos != child.dom) + pos = rm(pos); + pos = child.dom.nextSibling; + } + else { + parent.insertBefore(child.dom, pos); + } + } + if (pos && track && track.node == parent) + track.written = true; + while (pos) + pos = rm(pos); + } + else if (this.dirty & 1 /* Child */) { + for (let child of this.children) + if (child.dirty) { + child.sync(track); + child.dirty = 0 /* Not */; + } + } + } + reuseDOM(_dom) { } + localPosFromDOM(node, offset) { + let after; + if (node == this.dom) { + after = this.dom.childNodes[offset]; + } + else { + let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1; + for (;;) { + let parent = node.parentNode; + if (parent == this.dom) + break; + if (bias == 0 && parent.firstChild != parent.lastChild) { + if (node == parent.firstChild) + bias = -1; + else + bias = 1; } + node = parent; } + if (bias < 0) + after = node; + else + after = node.nextSibling; + } + if (after == this.dom.firstChild) return 0; - }; + while (after && !ContentView.get(after)) + after = after.nextSibling; + if (!after) + return this.length; + for (let i = 0, pos = 0;; i++) { + let child = this.children[i]; + if (child.dom == after) + return pos; + pos += child.length + child.breakAfter; + } } -} -function compareArray(a, b, compare) { - if (a.length != b.length) - return false; - for (let i = 0; i < a.length; i++) - if (!compare(a[i], b[i])) - return false; - return true; -} -function dynamicFacetSlot(addresses, facet, providers) { - let providerAddrs = providers.map(p => addresses[p.id]); - let providerTypes = providers.map(p => p.type); - let dynamic = providerAddrs.filter(p => !(p & 1)); - let idx = addresses[facet.id] >> 1; - return (state, tr) => { - let oldVal = state.values[idx], changed = oldVal === Uninitialized || !tr; - for (let dynAddr of dynamic) { - if (ensureAddr(state, dynAddr) & 1 /* Changed */) - changed = true; + domBoundsAround(from, to, offset = 0) { + let fromI = -1, fromStart = -1, toI = -1, toEnd = -1; + for (let i = 0, pos = offset, prevEnd = offset; i < this.children.length; i++) { + let child = this.children[i], end = pos + child.length; + if (pos < from && end > to) + return child.domBoundsAround(from, to, pos); + if (end >= from && fromI == -1) { + fromI = i; + fromStart = pos; + } + if (pos > to && child.dom.parentNode == this.dom) { + toI = i; + toEnd = prevEnd; + break; + } + prevEnd = end; + pos = end + child.breakAfter; } - if (!changed) - return 0; - let values = []; - for (let i = 0; i < providerAddrs.length; i++) { - let value = getAddr(state, providerAddrs[i]); - if (providerTypes[i] == 2 /* Multi */) - for (let val of value) - values.push(val); - else - values.push(value); + return { from: fromStart, to: toEnd < 0 ? offset + this.length : toEnd, + startDOM: (fromI ? this.children[fromI - 1].dom.nextSibling : null) || this.dom.firstChild, + endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null }; + } + markDirty(andParent = false) { + this.dirty |= 2 /* Node */; + this.markParentsDirty(andParent); + } + markParentsDirty(childList) { + for (let parent = this.parent; parent; parent = parent.parent) { + if (childList) + parent.dirty |= 2 /* Node */; + if (parent.dirty & 1 /* Child */) + return; + parent.dirty |= 1 /* Child */; + childList = false; } - let value = facet.combine(values); - if (oldVal !== Uninitialized && facet.compare(value, oldVal)) - return 0; - state.values[idx] = value; - return 1 /* Changed */; - }; -} -const initField = Facet.define({ static: true }); -/** -Fields can store additional information in an editor state, and -keep it in sync with the rest of the state. -*/ -class StateField { - constructor( - /** - @internal - */ - id, createF, updateF, compareF, - /** - @internal - */ - spec) { - this.id = id; - this.createF = createF; - this.updateF = updateF; - this.compareF = compareF; - this.spec = spec; - /** - @internal - */ - this.provides = undefined; } - /** - Define a state field. - */ - static define(config) { - let field = new StateField(nextID++, config.create, config.update, config.compare || ((a, b) => a === b), config); - if (config.provide) - field.provides = config.provide(field); - return field; + setParent(parent) { + if (this.parent != parent) { + this.parent = parent; + if (this.dirty) + this.markParentsDirty(true); + } } - create(state) { - let init = state.facet(initField).find(i => i.field == this); - return ((init === null || init === void 0 ? void 0 : init.create) || this.createF)(state); + setDOM(dom) { + if (this.dom) + this.dom.cmView = null; + this.dom = dom; + dom.cmView = this; } - /** - @internal - */ - slot(addresses) { - let idx = addresses[this.id] >> 1; - return (state, tr) => { - let oldVal = state.values[idx]; - if (oldVal === Uninitialized) { - state.values[idx] = this.create(state); - return 1 /* Changed */; - } - if (tr) { - let value = this.updateF(oldVal, tr); - if (!this.compareF(oldVal, value)) { - state.values[idx] = value; - return 1 /* Changed */; - } - } - return 0; - }; + get rootView() { + for (let v = this;;) { + let parent = v.parent; + if (!parent) + return v; + v = parent; + } } - /** - Returns an extension that enables this field and overrides the - way it is initialized. Can be useful when you need to provide a - non-default starting value for the field. - */ - init(create) { - return [this, initField.of({ field: this, create })]; + replaceChildren(from, to, children = noChildren) { + this.markDirty(); + for (let i = from; i < to; i++) { + let child = this.children[i]; + if (child.parent == this) + child.destroy(); + } + this.children.splice(from, to - from, ...children); + for (let i = 0; i < children.length; i++) + children[i].setParent(this); } - /** - State field instances can be used as - [`Extension`](https://codemirror.net/6/docs/ref/#state.Extension) values to enable the field in a - given state. - */ - get extension() { return this; } -} -const Prec_ = { lowest: 4, low: 3, default: 2, high: 1, highest: 0 }; -function prec(value) { - return (ext) => new PrecExtension(ext, value); -} -/** -By default extensions are registered in the order they are found -in the flattened form of nested array that was provided. -Individual extension values can be assigned a precedence to -override this. Extensions that do not have a precedence set get -the precedence of the nearest parent with a precedence, or -[`default`](https://codemirror.net/6/docs/ref/#state.Prec.default) if there is no such parent. The -final ordering of extensions is determined by first sorting by -precedence and then by order within each precedence. -*/ -const Prec = { - /** - The lowest precedence level. Meant for things that should end up - near the end of the extension order. - */ - lowest: prec(Prec_.lowest), - /** - A lower-than-default precedence, for extensions. - */ - low: prec(Prec_.low), - /** - The default precedence, which is also used for extensions - without an explicit precedence. - */ - default: prec(Prec_.default), - /** - A higher-than-default precedence, for extensions that should - come before those with default precedence. - */ - high: prec(Prec_.high), - /** - The highest precedence level, for extensions that should end up - near the start of the precedence ordering. - */ - highest: prec(Prec_.highest), - // FIXME Drop these in some future breaking version - /** - Backwards-compatible synonym for `Prec.lowest`. - */ - fallback: prec(Prec_.lowest), - /** - Backwards-compatible synonym for `Prec.high`. - */ - extend: prec(Prec_.high), - /** - Backwards-compatible synonym for `Prec.highest`. - */ - override: prec(Prec_.highest) -}; -class PrecExtension { - constructor(inner, prec) { - this.inner = inner; - this.prec = prec; + ignoreMutation(_rec) { return false; } + ignoreEvent(_event) { return false; } + childCursor(pos = this.length) { + return new ChildCursor(this.children, pos, this.children.length); } -} -/** -Extension compartments can be used to make a configuration -dynamic. By [wrapping](https://codemirror.net/6/docs/ref/#state.Compartment.of) part of your -configuration in a compartment, you can later -[replace](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) that part through a -transaction. -*/ -class Compartment { - /** - Create an instance of this compartment to add to your [state - configuration](https://codemirror.net/6/docs/ref/#state.EditorStateConfig.extensions). - */ - of(ext) { return new CompartmentInstance(this, ext); } - /** - Create an [effect](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) that - reconfigures this compartment. - */ - reconfigure(content) { - return Compartment.reconfigure.of({ compartment: this, extension: content }); + childPos(pos, bias = 1) { + return this.childCursor().findPos(pos, bias); } - /** - Get the current content of the compartment in the state, or - `undefined` if it isn't present. - */ - get(state) { - return state.config.compartments.get(this); + toString() { + let name = this.constructor.name.replace("View", ""); + return name + (this.children.length ? "(" + this.children.join() + ")" : + this.length ? "[" + (name == "Text" ? this.text : this.length) + "]" : "") + + (this.breakAfter ? "#" : ""); } -} -class CompartmentInstance { - constructor(compartment, inner) { - this.compartment = compartment; - this.inner = inner; + static get(node) { return node.cmView; } + get isEditable() { return true; } + merge(from, to, source, hasStart, openStart, openEnd) { + return false; } -} -class Configuration { - constructor(base, compartments, dynamicSlots, address, staticValues) { - this.base = base; - this.compartments = compartments; - this.dynamicSlots = dynamicSlots; - this.address = address; - this.staticValues = staticValues; - this.statusTemplate = []; - while (this.statusTemplate.length < dynamicSlots.length) - this.statusTemplate.push(0 /* Unresolved */); + become(other) { return false; } + // When this is a zero-length view with a side, this should return a + // number <= 0 to indicate it is before its position, or a + // number > 0 when after its position. + getSide() { return 0; } + destroy() { + this.parent = null; } - staticFacet(facet) { - let addr = this.address[facet.id]; - return addr == null ? facet.default : this.staticValues[addr >> 1]; +} +ContentView.prototype.breakAfter = 0; +// Remove a DOM node and return its next sibling. +function rm(dom) { + let next = dom.nextSibling; + dom.parentNode.removeChild(dom); + return next; +} +class ChildCursor { + constructor(children, pos, i) { + this.children = children; + this.pos = pos; + this.i = i; + this.off = 0; } - static resolve(base, compartments, oldState) { - let fields = []; - let facets = Object.create(null); - let newCompartments = new Map(); - for (let ext of flatten(base, compartments, newCompartments)) { - if (ext instanceof StateField) - fields.push(ext); - else - (facets[ext.facet.id] || (facets[ext.facet.id] = [])).push(ext); - } - let address = Object.create(null); - let staticValues = []; - let dynamicSlots = []; - let dynamicDeps = []; - for (let field of fields) { - address[field.id] = dynamicSlots.length << 1; - dynamicSlots.push(a => field.slot(a)); - dynamicDeps.push([]); + findPos(pos, bias = 1) { + for (;;) { + if (pos > this.pos || pos == this.pos && + (bias > 0 || this.i == 0 || this.children[this.i - 1].breakAfter)) { + this.off = pos - this.pos; + return this; + } + let next = this.children[--this.i]; + this.pos -= next.length + next.breakAfter; } - for (let id in facets) { - let providers = facets[id], facet = providers[0].facet; - if (providers.every(p => p.type == 0 /* Static */)) { - address[facet.id] = (staticValues.length << 1) | 1; - let value = facet.combine(providers.map(p => p.value)); - let oldAddr = oldState ? oldState.config.address[facet.id] : null; - if (oldAddr != null) { - let oldVal = getAddr(oldState, oldAddr); - if (facet.compare(value, oldVal)) - value = oldVal; - } - staticValues.push(value); + } +} +function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart, openStart, openEnd) { + let { children } = parent; + let before = children.length ? children[fromI] : null; + let last = insert.length ? insert[insert.length - 1] : null; + let breakAtEnd = last ? last.breakAfter : breakAtStart; + // Change within a single child + if (fromI == toI && before && !breakAtStart && !breakAtEnd && insert.length < 2 && + before.merge(fromOff, toOff, insert.length ? last : null, fromOff == 0, openStart, openEnd)) + return; + if (toI < children.length) { + let after = children[toI]; + // Make sure the end of the child after the update is preserved in `after` + if (after && toOff < after.length) { + // If we're splitting a child, separate part of it to avoid that + // being mangled when updating the child before the update. + if (fromI == toI) { + after = after.split(toOff); + toOff = 0; + } + // If the element after the replacement should be merged with + // the last replacing element, update `content` + if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) { + insert[insert.length - 1] = after; } else { - for (let p of providers) { - if (p.type == 0 /* Static */) { - address[p.id] = (staticValues.length << 1) | 1; - staticValues.push(p.value); - } - else { - address[p.id] = dynamicSlots.length << 1; - dynamicSlots.push(a => p.dynamicSlot(a)); - dynamicDeps.push(p.dependencies.filter(d => typeof d != "string").map(d => d.id)); - } - } - address[facet.id] = dynamicSlots.length << 1; - dynamicSlots.push(a => dynamicFacetSlot(a, facet, providers)); - dynamicDeps.push(providers.filter(p => p.type != 0 /* Static */).map(d => d.id)); + // Remove the start of the after element, if necessary, and + // add it to `content`. + if (toOff) + after.merge(0, toOff, null, false, 0, openEnd); + insert.push(after); } } - let dynamicValues = dynamicSlots.map(_ => Uninitialized); - if (oldState) { - let canReuse = (id, depth) => { - if (depth > 7) - return false; - let addr = address[id]; - if (!(addr & 1)) - return dynamicDeps[addr >> 1].every(id => canReuse(id, depth + 1)); - let oldAddr = oldState.config.address[id]; - return oldAddr != null && getAddr(oldState, oldAddr) == staticValues[addr >> 1]; - }; - // Copy over old values for shared facets/fields, if we can - // prove that they don't need to be recomputed. - for (let id in address) { - let cur = address[id], prev = oldState.config.address[id]; - if (prev != null && (cur & 1) == 0 && canReuse(+id, 0)) - dynamicValues[cur >> 1] = getAddr(oldState, prev); - } + else if (after === null || after === void 0 ? void 0 : after.breakAfter) { + // The element at `toI` is entirely covered by this range. + // Preserve its line break, if any. + if (last) + last.breakAfter = 1; + else + breakAtStart = 1; } - return { - configuration: new Configuration(base, newCompartments, dynamicSlots.map(f => f(address)), address, staticValues), - values: dynamicValues - }; + // Since we've handled the next element from the current elements + // now, make sure `toI` points after that. + toI++; } -} -function flatten(extension, compartments, newCompartments) { - let result = [[], [], [], [], []]; - let seen = new Map(); - function inner(ext, prec) { - let known = seen.get(ext); - if (known != null) { - if (known >= prec) - return; - let found = result[known].indexOf(ext); - if (found > -1) - result[known].splice(found, 1); - if (ext instanceof CompartmentInstance) - newCompartments.delete(ext.compartment); - } - seen.set(ext, prec); - if (Array.isArray(ext)) { - for (let e of ext) - inner(e, prec); - } - else if (ext instanceof CompartmentInstance) { - if (newCompartments.has(ext.compartment)) - throw new RangeError(`Duplicate use of compartment in extensions`); - let content = compartments.get(ext.compartment) || ext.inner; - newCompartments.set(ext.compartment, content); - inner(content, prec); - } - else if (ext instanceof PrecExtension) { - inner(ext.inner, ext.prec); + if (before) { + before.breakAfter = breakAtStart; + if (fromOff > 0) { + if (!breakAtStart && insert.length && before.merge(fromOff, before.length, insert[0], false, openStart, 0)) { + before.breakAfter = insert.shift().breakAfter; + } + else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) { + before.merge(fromOff, before.length, null, false, openStart, 0); + } + fromI++; } - else if (ext instanceof StateField) { - result[prec].push(ext); - if (ext.provides) - inner(ext.provides, prec); + } + // Try to merge widgets on the boundaries of the replacement + while (fromI < toI && insert.length) { + if (children[toI - 1].become(insert[insert.length - 1])) { + toI--; + insert.pop(); + openEnd = insert.length ? 0 : openStart; } - else if (ext instanceof FacetProvider) { - result[prec].push(ext); - if (ext.facet.extensions) - inner(ext.facet.extensions, prec); + else if (children[fromI].become(insert[0])) { + fromI++; + insert.shift(); + openStart = insert.length ? 0 : openEnd; } - else { - let content = ext.extension; - if (!content) - throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`); - inner(content, prec); + else { + break; } } - inner(extension, Prec_.default); - return result.reduce((a, b) => a.concat(b)); -} -const Uninitialized = {}; -function ensureAddr(state, addr) { - if (addr & 1) - return 2 /* Computed */; - let idx = addr >> 1; - let status = state.status[idx]; - if (status == 4 /* Computing */) - throw new Error("Cyclic dependency between fields and/or facets"); - if (status & 2 /* Computed */) - return status; - state.status[idx] = 4 /* Computing */; - let changed = state.config.dynamicSlots[idx](state, state.applying); - return state.status[idx] = 2 /* Computed */ | changed; + if (!insert.length && fromI && toI < children.length && !children[fromI - 1].breakAfter && + children[toI].merge(0, 0, children[fromI - 1], false, openStart, openEnd)) + fromI--; + if (fromI < toI || insert.length) + parent.replaceChildren(fromI, toI, insert); } -function getAddr(state, addr) { - return addr & 1 ? state.config.staticValues[addr >> 1] : state.values[addr >> 1]; +function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) { + let cur = parent.childCursor(); + let { i: toI, off: toOff } = cur.findPos(to, 1); + let { i: fromI, off: fromOff } = cur.findPos(from, -1); + let dLen = from - to; + for (let view of insert) + dLen += view.length; + parent.length += dLen; + replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd); } -const languageData = Facet.define(); -const allowMultipleSelections = Facet.define({ - combine: values => values.some(v => v), - static: true -}); -const lineSeparator = Facet.define({ - combine: values => values.length ? values[0] : undefined, - static: true -}); -const changeFilter = Facet.define(); -const transactionFilter = Facet.define(); -const transactionExtender = Facet.define(); -const readOnly = Facet.define({ - combine: values => values.length ? values[0] : false -}); +let [nav, doc] = typeof navigator != "undefined" + ? [navigator, document] + : [{ userAgent: "", vendor: "", platform: "" }, { documentElement: { style: {} } }]; +const ie_edge = /Edge\/(\d+)/.exec(nav.userAgent); +const ie_upto10 = /MSIE \d/.test(nav.userAgent); +const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent); +const ie = !!(ie_upto10 || ie_11up || ie_edge); +const gecko = !ie && /gecko\/(\d+)/i.test(nav.userAgent); +const chrome = !ie && /Chrome\/(\d+)/.exec(nav.userAgent); +const webkit = "webkitFontSmoothing" in doc.documentElement.style; +const safari = !ie && /Apple Computer/.test(nav.vendor); +const ios = safari && (/Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2); +var browser = { + mac: ios || /Mac/.test(nav.platform), + windows: /Win/.test(nav.platform), + linux: /Linux|X11/.test(nav.platform), + ie, + ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0, + gecko, + gecko_version: gecko ? +(/Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0, + chrome: !!chrome, + chrome_version: chrome ? +chrome[1] : 0, + ios, + android: /Android\b/.test(nav.userAgent), + webkit, + safari, + webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0, + tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size" +}; -/** -Annotations are tagged values that are used to add metadata to -transactions in an extensible way. They should be used to model -things that effect the entire transaction (such as its [time -stamp](https://codemirror.net/6/docs/ref/#state.Transaction^time) or information about its -[origin](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent)). For effects that happen -_alongside_ the other changes made by the transaction, [state -effects](https://codemirror.net/6/docs/ref/#state.StateEffect) are more appropriate. -*/ -class Annotation { - /** - @internal - */ - constructor( - /** - The annotation type. - */ - type, - /** - The value of this annotation. - */ - value) { - this.type = type; - this.value = value; +const MaxJoinLen = 256; +class TextView extends ContentView { + constructor(text) { + super(); + this.text = text; } - /** - Define a new type of annotation. - */ - static define() { return new AnnotationType(); } -} -/** -Marker that identifies a type of [annotation](https://codemirror.net/6/docs/ref/#state.Annotation). -*/ -class AnnotationType { - /** - Create an instance of this annotation. - */ - of(value) { return new Annotation(this, value); } -} -/** -Representation of a type of state effect. Defined with -[`StateEffect.define`](https://codemirror.net/6/docs/ref/#state.StateEffect^define). -*/ -class StateEffectType { - /** - @internal - */ - constructor( - // The `any` types in these function types are there to work - // around TypeScript issue #37631, where the type guard on - // `StateEffect.is` mysteriously stops working when these properly - // have type `Value`. - /** - @internal - */ - map) { - this.map = map; + get length() { return this.text.length; } + createDOM(textDOM) { + this.setDOM(textDOM || document.createTextNode(this.text)); } - /** - Create a [state effect](https://codemirror.net/6/docs/ref/#state.StateEffect) instance of this - type. - */ - of(value) { return new StateEffect(this, value); } -} -/** -State effects can be used to represent additional effects -associated with a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction.effects). They -are often useful to model changes to custom [state -fields](https://codemirror.net/6/docs/ref/#state.StateField), when those changes aren't implicit in -document or selection changes. -*/ -class StateEffect { - /** - @internal - */ - constructor( - /** - @internal - */ - type, - /** - The value of this effect. - */ - value) { - this.type = type; - this.value = value; + sync(track) { + if (!this.dom) + this.createDOM(); + if (this.dom.nodeValue != this.text) { + if (track && track.node == this.dom) + track.written = true; + this.dom.nodeValue = this.text; + } } - /** - Map this effect through a position mapping. Will return - `undefined` when that ends up deleting the effect. - */ - map(mapping) { - let mapped = this.type.map(this.value, mapping); - return mapped === undefined ? undefined : mapped == this.value ? this : new StateEffect(this.type, mapped); + reuseDOM(dom) { + if (dom.nodeType == 3) + this.createDOM(dom); } - /** - Tells you whether this effect object is of a given - [type](https://codemirror.net/6/docs/ref/#state.StateEffectType). - */ - is(type) { return this.type == type; } - /** - Define a new effect type. The type parameter indicates the type - of values that his effect holds. - */ - static define(spec = {}) { - return new StateEffectType(spec.map || (v => v)); + merge(from, to, source) { + if (source && (!(source instanceof TextView) || this.length - (to - from) + source.length > MaxJoinLen)) + return false; + this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to); + this.markDirty(); + return true; } - /** - Map an array of effects through a change set. - */ - static mapEffects(effects, mapping) { - if (!effects.length) - return effects; - let result = []; - for (let effect of effects) { - let mapped = effect.map(mapping); - if (mapped) - result.push(mapped); - } + split(from) { + let result = new TextView(this.text.slice(from)); + this.text = this.text.slice(0, from); + this.markDirty(); return result; } + localPosFromDOM(node, offset) { + return node == this.dom ? offset : offset ? this.text.length : 0; + } + domAtPos(pos) { return new DOMPos(this.dom, pos); } + domBoundsAround(_from, _to, offset) { + return { from: offset, to: offset + this.length, startDOM: this.dom, endDOM: this.dom.nextSibling }; + } + coordsAt(pos, side) { + return textCoords(this.dom, pos, side); + } } -/** -This effect can be used to reconfigure the root extensions of -the editor. Doing this will discard any extensions -[appended](https://codemirror.net/6/docs/ref/#state.StateEffect^appendConfig), but does not reset -the content of [reconfigured](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) -compartments. -*/ -StateEffect.reconfigure = StateEffect.define(); -/** -Append extensions to the top-level configuration of the editor. -*/ -StateEffect.appendConfig = StateEffect.define(); -/** -Changes to the editor state are grouped into transactions. -Typically, a user action creates a single transaction, which may -contain any number of document changes, may change the selection, -or have other effects. Create a transaction by calling -[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update). -*/ -class Transaction { - /** - @internal - */ - constructor( - /** - The state from which the transaction starts. - */ - startState, - /** - The document changes made by this transaction. - */ - changes, - /** - The selection set by this transaction, or undefined if it - doesn't explicitly set a selection. - */ - selection, - /** - The effects added to the transaction. - */ - effects, - /** - @internal - */ - annotations, - /** - Whether the selection should be scrolled into view after this - transaction is dispatched. - */ - scrollIntoView) { - this.startState = startState; - this.changes = changes; - this.selection = selection; - this.effects = effects; - this.annotations = annotations; - this.scrollIntoView = scrollIntoView; - /** - @internal - */ - this._doc = null; - /** - @internal - */ - this._state = null; - if (selection) - checkSelection(selection, changes.newLength); - if (!annotations.some((a) => a.type == Transaction.time)) - this.annotations = annotations.concat(Transaction.time.of(Date.now())); +class MarkView extends ContentView { + constructor(mark, children = [], length = 0) { + super(); + this.mark = mark; + this.children = children; + this.length = length; + for (let ch of children) + ch.setParent(this); } - /** - The new document produced by the transaction. Contrary to - [`.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state)`.doc`, accessing this won't - force the entire new state to be computed right away, so it is - recommended that [transaction - filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) use this getter - when they need to look at the new document. - */ - get newDoc() { - return this._doc || (this._doc = this.changes.apply(this.startState.doc)); + setAttrs(dom) { + clearAttributes(dom); + if (this.mark.class) + dom.className = this.mark.class; + if (this.mark.attrs) + for (let name in this.mark.attrs) + dom.setAttribute(name, this.mark.attrs[name]); + return dom; } - /** - The new selection produced by the transaction. If - [`this.selection`](https://codemirror.net/6/docs/ref/#state.Transaction.selection) is undefined, - this will [map](https://codemirror.net/6/docs/ref/#state.EditorSelection.map) the start state's - current selection through the changes made by the transaction. - */ - get newSelection() { - return this.selection || this.startState.selection.map(this.changes); + reuseDOM(node) { + if (node.nodeName == this.mark.tagName.toUpperCase()) { + this.setDOM(node); + this.dirty |= 4 /* Attrs */ | 2 /* Node */; + } } - /** - The new state created by the transaction. Computed on demand - (but retained for subsequent access), so itis recommended not to - access it in [transaction - filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) when possible. - */ - get state() { - if (!this._state) - this.startState.applyTransaction(this); - return this._state; + sync(track) { + if (!this.dom) + this.setDOM(this.setAttrs(document.createElement(this.mark.tagName))); + else if (this.dirty & 4 /* Attrs */) + this.setAttrs(this.dom); + super.sync(track); } - /** - Get the value of the given annotation type, if any. - */ - annotation(type) { - for (let ann of this.annotations) - if (ann.type == type) - return ann.value; - return undefined; + merge(from, to, source, _hasStart, openStart, openEnd) { + if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) || + (from && openStart <= 0) || (to < this.length && openEnd <= 0))) + return false; + mergeChildrenInto(this, from, to, source ? source.children : [], openStart - 1, openEnd - 1); + this.markDirty(); + return true; } - /** - Indicates whether the transaction changed the document. - */ - get docChanged() { return !this.changes.empty; } - /** - Indicates whether this transaction reconfigures the state - (through a [configuration compartment](https://codemirror.net/6/docs/ref/#state.Compartment) or - with a top-level configuration - [effect](https://codemirror.net/6/docs/ref/#state.StateEffect^reconfigure). - */ - get reconfigured() { return this.startState.config != this.state.config; } - /** - Returns true if the transaction has a [user - event](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent) annotation that is equal to - or more specific than `event`. For example, if the transaction - has `"select.pointer"` as user event, `"select"` and - `"select.pointer"` will match it. - */ - isUserEvent(event) { - let e = this.annotation(Transaction.userEvent); - return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == ".")); + split(from) { + let result = [], off = 0, detachFrom = -1, i = 0; + for (let elt of this.children) { + let end = off + elt.length; + if (end > from) + result.push(off < from ? elt.split(from - off) : elt); + if (detachFrom < 0 && off >= from) + detachFrom = i; + off = end; + i++; + } + let length = this.length - from; + this.length = from; + if (detachFrom > -1) { + this.children.length = detachFrom; + this.markDirty(); + } + return new MarkView(this.mark, result, length); + } + domAtPos(pos) { + return inlineDOMAtPos(this.dom, this.children, pos); + } + coordsAt(pos, side) { + return coordsInChildren(this, pos, side); } } -/** -Annotation used to store transaction timestamps. -*/ -Transaction.time = Annotation.define(); -/** -Annotation used to associate a transaction with a user interface -event. Holds a string identifying the event, using a -dot-separated format to support attaching more specific -information. The events used by the core libraries are: - - - `"input"` when content is entered - - `"input.type"` for typed input - - `"input.type.compose"` for composition - - `"input.paste"` for pasted input - - `"input.drop"` when adding content with drag-and-drop - - `"input.complete"` when autocompleting - - `"delete"` when the user deletes content - - `"delete.selection"` when deleting the selection - - `"delete.forward"` when deleting forward from the selection - - `"delete.backward"` when deleting backward from the selection - - `"delete.cut"` when cutting to the clipboard - - `"move"` when content is moved - - `"move.drop"` when content is moved within the editor through drag-and-drop - - `"select"` when explicitly changing the selection - - `"select.pointer"` when selecting with a mouse or other pointing device - - `"undo"` and `"redo"` for history actions - -Use [`isUserEvent`](https://codemirror.net/6/docs/ref/#state.Transaction.isUserEvent) to check -whether the annotation matches a given event. -*/ -Transaction.userEvent = Annotation.define(); -/** -Annotation indicating whether a transaction should be added to -the undo history or not. -*/ -Transaction.addToHistory = Annotation.define(); -/** -Annotation indicating (when present and true) that a transaction -represents a change made by some other actor, not the user. This -is used, for example, to tag other people's changes in -collaborative editing. -*/ -Transaction.remote = Annotation.define(); -function joinRanges(a, b) { - let result = []; - for (let iA = 0, iB = 0;;) { - let from, to; - if (iA < a.length && (iB == b.length || b[iB] >= a[iA])) { - from = a[iA++]; - to = a[iA++]; +function textCoords(text, pos, side) { + let length = text.nodeValue.length; + if (pos > length) + pos = length; + let from = pos, to = pos, flatten = 0; + if (pos == 0 && side < 0 || pos == length && side >= 0) { + if (!(browser.chrome || browser.gecko)) { // These browsers reliably return valid rectangles for empty ranges + if (pos) { + from--; + flatten = 1; + } // FIXME this is wrong in RTL text + else { + to++; + flatten = -1; + } + } + } + else { + if (side < 0) + from--; + else + to++; + } + let rects = textRange(text, from, to).getClientRects(); + if (!rects.length) + return Rect0; + let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1]; + if (browser.safari && !flatten && rect.width == 0) + rect = Array.prototype.find.call(rects, r => r.width) || rect; + return flatten ? flattenRect(rect, flatten < 0) : rect || null; +} +// Also used for collapsed ranges that don't have a placeholder widget! +class WidgetView extends ContentView { + constructor(widget, length, side) { + super(); + this.widget = widget; + this.length = length; + this.side = side; + } + static create(widget, length, side) { + return new (widget.customView || WidgetView)(widget, length, side); + } + split(from) { + let result = WidgetView.create(this.widget, this.length - from, this.side); + this.length -= from; + return result; + } + sync() { + if (!this.dom || !this.widget.updateDOM(this.dom)) { + this.setDOM(this.widget.toDOM(this.editorView)); + this.dom.contentEditable = "false"; } - else if (iB < b.length) { - from = b[iB++]; - to = b[iB++]; + } + getSide() { return this.side; } + merge(from, to, source, hasStart, openStart, openEnd) { + if (source && (!(source instanceof WidgetView) || !this.widget.compare(source.widget) || + from > 0 && openStart <= 0 || to < this.length && openEnd <= 0)) + return false; + this.length = from + (source ? source.length : 0) + (this.length - to); + return true; + } + become(other) { + if (other.length == this.length && other instanceof WidgetView && other.side == this.side) { + if (this.widget.constructor == other.widget.constructor) { + if (!this.widget.eq(other.widget)) + this.markDirty(true); + this.widget = other.widget; + return true; + } } - else - return result; - if (!result.length || result[result.length - 1] < from) - result.push(from, to); - else if (result[result.length - 1] < to) - result[result.length - 1] = to; + return false; } -} -function mergeTransaction(a, b, sequential) { - var _a; - let mapForA, mapForB, changes; - if (sequential) { - mapForA = b.changes; - mapForB = ChangeSet.empty(b.changes.length); - changes = a.changes.compose(b.changes); + ignoreMutation() { return true; } + ignoreEvent(event) { return this.widget.ignoreEvent(event); } + get overrideDOMText() { + if (this.length == 0) + return text.Text.empty; + let top = this; + while (top.parent) + top = top.parent; + let view = top.editorView, text$1 = view && view.state.doc, start = this.posAtStart; + return text$1 ? text$1.slice(start, start + this.length) : text.Text.empty; } - else { - mapForA = b.changes.map(a.changes); - mapForB = a.changes.mapDesc(b.changes, true); - changes = a.changes.compose(mapForA); + domAtPos(pos) { + return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length); + } + domBoundsAround() { return null; } + coordsAt(pos, side) { + let rects = this.dom.getClientRects(), rect = null; + if (!rects.length) + return Rect0; + for (let i = pos > 0 ? rects.length - 1 : 0;; i += (pos > 0 ? -1 : 1)) { + rect = rects[i]; + if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom) + break; + } + return (pos == 0 && side > 0 || pos == this.length && side <= 0) ? rect : flattenRect(rect, pos == 0); + } + get isEditable() { return false; } + destroy() { + super.destroy(); + if (this.dom) + this.widget.destroy(this.dom); } - return { - changes, - selection: b.selection ? b.selection.map(mapForB) : (_a = a.selection) === null || _a === void 0 ? void 0 : _a.map(mapForA), - effects: StateEffect.mapEffects(a.effects, mapForA).concat(StateEffect.mapEffects(b.effects, mapForB)), - annotations: a.annotations.length ? a.annotations.concat(b.annotations) : b.annotations, - scrollIntoView: a.scrollIntoView || b.scrollIntoView - }; } -function resolveTransactionInner(state, spec, docSize) { - let sel = spec.selection, annotations = asArray(spec.annotations); - if (spec.userEvent) - annotations = annotations.concat(Transaction.userEvent.of(spec.userEvent)); - return { - changes: spec.changes instanceof ChangeSet ? spec.changes - : ChangeSet.of(spec.changes || [], docSize, state.facet(lineSeparator)), - selection: sel && (sel instanceof EditorSelection ? sel : EditorSelection.single(sel.anchor, sel.head)), - effects: asArray(spec.effects), - annotations, - scrollIntoView: !!spec.scrollIntoView - }; +class CompositionView extends WidgetView { + domAtPos(pos) { return new DOMPos(this.widget.text, pos); } + sync() { this.setDOM(this.widget.toDOM()); } + localPosFromDOM(node, offset) { + return !offset ? 0 : node.nodeType == 3 ? Math.min(offset, this.length) : this.length; + } + ignoreMutation() { return false; } + get overrideDOMText() { return null; } + coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); } + get isEditable() { return true; } } -function resolveTransaction(state, specs, filter) { - let s = resolveTransactionInner(state, specs.length ? specs[0] : {}, state.doc.length); - if (specs.length && specs[0].filter === false) - filter = false; - for (let i = 1; i < specs.length; i++) { - if (specs[i].filter === false) - filter = false; - let seq = !!specs[i].sequential; - s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq); +// Use two characters on Android, to prevent Chrome from closing the +// virtual keyboard when backspacing after a widget (#602). +const ZeroWidthSpace = browser.android ? "\u200b\u200b" : "\u200b"; +// These are drawn around uneditable widgets to avoid a number of +// browser bugs that show up when the cursor is directly next to +// uneditable inline content. +class WidgetBufferView extends ContentView { + constructor(side) { + super(); + this.side = side; + } + get length() { return 0; } + merge() { return false; } + become(other) { + return other instanceof WidgetBufferView && other.side == this.side; + } + split() { return new WidgetBufferView(this.side); } + sync() { + if (!this.dom) + this.setDOM(document.createTextNode(ZeroWidthSpace)); + else if (this.dirty && this.dom.nodeValue != ZeroWidthSpace) + this.dom.nodeValue = ZeroWidthSpace; + } + getSide() { return this.side; } + domAtPos(pos) { return DOMPos.before(this.dom); } + localPosFromDOM() { return 0; } + domBoundsAround() { return null; } + coordsAt(pos) { + let rects = clientRectsFor(this.dom); + return rects[rects.length - 1] || null; + } + get overrideDOMText() { + return text.Text.of([this.dom.nodeValue.replace(/\u200b/g, "")]); } - let tr = new Transaction(state, s.changes, s.selection, s.effects, s.annotations, s.scrollIntoView); - return extendTransaction(filter ? filterTransaction(tr) : tr); } -// Finish a transaction by applying filters if necessary. -function filterTransaction(tr) { - let state = tr.startState; - // Change filters - let result = true; - for (let filter of state.facet(changeFilter)) { - let value = filter(tr); - if (value === false) { - result = false; +TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren; +function inlineDOMAtPos(dom, children, pos) { + let i = 0; + for (let off = 0; i < children.length; i++) { + let child = children[i], end = off + child.length; + if (end == off && child.getSide() <= 0) + continue; + if (pos > off && pos < end && child.dom.parentNode == dom) + return child.domAtPos(pos - off); + if (pos <= off) break; - } - if (Array.isArray(value)) - result = result === true ? value : joinRanges(result, value); - } - if (result !== true) { - let changes, back; - if (result === false) { - back = tr.changes.invertedDesc; - changes = ChangeSet.empty(state.doc.length); - } - else { - let filtered = tr.changes.filter(result); - changes = filtered.changes; - back = filtered.filtered.invertedDesc; - } - tr = new Transaction(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView); + off = end; } - // Transaction filters - let filters = state.facet(transactionFilter); - for (let i = filters.length - 1; i >= 0; i--) { - let filtered = filters[i](tr); - if (filtered instanceof Transaction) - tr = filtered; - else if (Array.isArray(filtered) && filtered.length == 1 && filtered[0] instanceof Transaction) - tr = filtered[0]; - else - tr = resolveTransaction(state, asArray(filtered), false); + for (; i > 0; i--) { + let before = children[i - 1].dom; + if (before.parentNode == dom) + return DOMPos.after(before); } - return tr; + return new DOMPos(dom, 0); } -function extendTransaction(tr) { - let state = tr.startState, extenders = state.facet(transactionExtender), spec = tr; - for (let i = extenders.length - 1; i >= 0; i--) { - let extension = extenders[i](tr); - if (extension && Object.keys(extension).length) - spec = mergeTransaction(tr, resolveTransactionInner(state, extension, tr.changes.newLength), true); +// Assumes `view`, if a mark view, has precisely 1 child. +function joinInlineInto(parent, view, open) { + let last, { children } = parent; + if (open > 0 && view instanceof MarkView && children.length && + (last = children[children.length - 1]) instanceof MarkView && last.mark.eq(view.mark)) { + joinInlineInto(last, view.children[0], open - 1); } - return spec == tr ? tr : new Transaction(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView); + else { + children.push(view); + view.setParent(parent); + } + parent.length += view.length; } -const none = []; -function asArray(value) { - return value == null ? none : Array.isArray(value) ? value : [value]; +function coordsInChildren(view, pos, side) { + for (let off = 0, i = 0; i < view.children.length; i++) { + let child = view.children[i], end = off + child.length, next; + if ((side <= 0 || end == view.length || child.getSide() > 0 ? end >= pos : end > pos) && + (pos < end || i + 1 == view.children.length || (next = view.children[i + 1]).length || next.getSide() > 0)) { + let flatten = 0; + if (end == off) { + if (child.getSide() <= 0) + continue; + flatten = side = -child.getSide(); + } + let rect = child.coordsAt(pos - off, side); + return flatten && rect ? flattenRect(rect, side < 0) : rect; + } + off = end; + } + let last = view.dom.lastChild; + if (!last) + return view.dom.getBoundingClientRect(); + let rects = clientRectsFor(last); + return rects[rects.length - 1] || null; } -/** -The categories produced by a [character -categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer). These are used -do things like selecting by word. -*/ -exports.CharCategory = void 0; -(function (CharCategory) { - /** - Word characters. - */ - CharCategory[CharCategory["Word"] = 0] = "Word"; - /** - Whitespace. - */ - CharCategory[CharCategory["Space"] = 1] = "Space"; - /** - Anything else. - */ - CharCategory[CharCategory["Other"] = 2] = "Other"; -})(exports.CharCategory || (exports.CharCategory = {})); -const nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; -let wordChar; -try { - wordChar = new RegExp("[\\p{Alphabetic}\\p{Number}_]", "u"); +function combineAttrs(source, target) { + for (let name in source) { + if (name == "class" && target.class) + target.class += " " + source.class; + else if (name == "style" && target.style) + target.style += ";" + source.style; + else + target[name] = source[name]; + } + return target; } -catch (_) { } -function hasWordChar(str) { - if (wordChar) - return wordChar.test(str); - for (let i = 0; i < str.length; i++) { - let ch = str[i]; - if (/\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))) - return true; +function attrsEq(a, b) { + if (a == b) + return true; + if (!a || !b) + return false; + let keysA = Object.keys(a), keysB = Object.keys(b); + if (keysA.length != keysB.length) + return false; + for (let key of keysA) { + if (keysB.indexOf(key) == -1 || a[key] !== b[key]) + return false; } - return false; + return true; } -function makeCategorizer(wordChars) { - return (char) => { - if (!/\S/.test(char)) - return exports.CharCategory.Space; - if (hasWordChar(char)) - return exports.CharCategory.Word; - for (let i = 0; i < wordChars.length; i++) - if (char.indexOf(wordChars[i]) > -1) - return exports.CharCategory.Word; - return exports.CharCategory.Other; - }; +function updateAttrs(dom, prev, attrs) { + if (prev) + for (let name in prev) + if (!(attrs && name in attrs)) + dom.removeAttribute(name); + if (attrs) + for (let name in attrs) + if (!(prev && prev[name] == attrs[name])) + dom.setAttribute(name, attrs[name]); } /** -The editor state class is a persistent (immutable) data structure. -To update a state, you [create](https://codemirror.net/6/docs/ref/#state.EditorState.update) a -[transaction](https://codemirror.net/6/docs/ref/#state.Transaction), which produces a _new_ state -instance, without modifying the original object. - -As such, _never_ mutate properties of a state directly. That'll -just break things. +Widgets added to the content are described by subclasses of this +class. Using a description object like that makes it possible to +delay creating of the DOM structure for a widget until it is +needed, and to avoid redrawing widgets even when the decorations +that define them are recreated. */ -class EditorState { +class WidgetType { /** - @internal + Compare this instance to another instance of the same type. + (TypeScript can't express this, but only instances of the same + specific class will be passed to this method.) This is used to + avoid redrawing widgets when they are replaced by a new + decoration of the same type. The default implementation just + returns `false`, which will cause new instances of the widget to + always be redrawn. */ - constructor( + eq(_widget) { return false; } /** - @internal + Update a DOM element created by a widget of the same type (but + different, non-`eq` content) to reflect this widget. May return + true to indicate that it could update, false to indicate it + couldn't (in which case the widget will be redrawn). The default + implementation just returns false. */ - config, + updateDOM(_dom) { return false; } /** - The current document. + @internal */ - doc, + compare(other) { + return this == other || this.constructor == other.constructor && this.eq(other); + } /** - The current selection. + The estimated height this widget will have, to be used when + estimating the height of content that hasn't been drawn. May + return -1 to indicate you don't know. The default implementation + returns -1. */ - selection, + get estimatedHeight() { return -1; } /** - @internal + Can be used to configure which kinds of events inside the widget + should be ignored by the editor. The default is to ignore all + events. */ - values, tr = null) { - this.config = config; - this.doc = doc; - this.selection = selection; - this.values = values; - /** - @internal - */ - this.applying = null; - this.status = config.statusTemplate.slice(); - this.applying = tr; - // Fill in the computed state immediately, so that further queries - // for it made during the update return this state - if (tr) - tr._state = this; - for (let i = 0; i < this.config.dynamicSlots.length; i++) - ensureAddr(this, i << 1); - this.applying = null; - } - field(field, require = true) { - let addr = this.config.address[field.id]; - if (addr == null) { - if (require) - throw new RangeError("Field is not present in this state"); - return undefined; - } - ensureAddr(this, addr); - return getAddr(this, addr); - } + ignoreEvent(_event) { return true; } /** - Create a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction) that updates this - state. Any number of [transaction specs](https://codemirror.net/6/docs/ref/#state.TransactionSpec) - can be passed. Unless - [`sequential`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.sequential) is set, the - [changes](https://codemirror.net/6/docs/ref/#state.TransactionSpec.changes) (if any) of each spec - are assumed to start in the _current_ document (not the document - produced by previous specs), and its - [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) and - [effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) are assumed to refer - to the document created by its _own_ changes. The resulting - transaction contains the combined effect of all the different - specs. For [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection), later - specs take precedence over earlier ones. + @internal */ - update(...specs) { - return resolveTransaction(this, specs, true); - } + get customView() { return null; } /** - @internal + This is called when the an instance of the widget is removed + from the editor view. */ - applyTransaction(tr) { - let conf = this.config, { base, compartments } = conf; - for (let effect of tr.effects) { - if (effect.is(Compartment.reconfigure)) { - if (conf) { - compartments = new Map; - conf.compartments.forEach((val, key) => compartments.set(key, val)); - conf = null; - } - compartments.set(effect.value.compartment, effect.value.extension); - } - else if (effect.is(StateEffect.reconfigure)) { - conf = null; - base = effect.value; - } - else if (effect.is(StateEffect.appendConfig)) { - conf = null; - base = asArray(base).concat(effect.value); - } - } - let startValues; - if (!conf) { - let resolved = Configuration.resolve(base, compartments, this); - conf = resolved.configuration; - let intermediateState = new EditorState(conf, this.doc, this.selection, resolved.values, null); - startValues = intermediateState.values; - } - else { - startValues = tr.startState.values.slice(); - } - new EditorState(conf, tr.newDoc, tr.newSelection, startValues, tr); - } + destroy(_dom) { } +} +/** +The different types of blocks that can occur in an editor view. +*/ +exports.BlockType = void 0; +(function (BlockType) { /** - Create a [transaction spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec) that - replaces every selection range with the given content. + A line of text. */ - replaceSelection(text) { - if (typeof text == "string") - text = this.toText(text); - return this.changeByRange(range => ({ changes: { from: range.from, to: range.to, insert: text }, - range: EditorSelection.cursor(range.from + text.length) })); - } + BlockType[BlockType["Text"] = 0] = "Text"; /** - Create a set of changes and a new selection by running the given - function for each range in the active selection. The function - can return an optional set of changes (in the coordinate space - of the start document), plus an updated range (in the coordinate - space of the document produced by the call's own changes). This - method will merge all the changes and ranges into a single - changeset and selection, and return it as a [transaction - spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec), which can be passed to - [`update`](https://codemirror.net/6/docs/ref/#state.EditorState.update). + A block widget associated with the position after it. */ - changeByRange(f) { - let sel = this.selection; - let result1 = f(sel.ranges[0]); - let changes = this.changes(result1.changes), ranges = [result1.range]; - let effects = asArray(result1.effects); - for (let i = 1; i < sel.ranges.length; i++) { - let result = f(sel.ranges[i]); - let newChanges = this.changes(result.changes), newMapped = newChanges.map(changes); - for (let j = 0; j < i; j++) - ranges[j] = ranges[j].map(newMapped); - let mapBy = changes.mapDesc(newChanges, true); - ranges.push(result.range.map(mapBy)); - changes = changes.compose(newMapped); - effects = StateEffect.mapEffects(effects, newMapped).concat(StateEffect.mapEffects(asArray(result.effects), mapBy)); - } - return { - changes, - selection: EditorSelection.create(ranges, sel.mainIndex), - effects - }; - } + BlockType[BlockType["WidgetBefore"] = 1] = "WidgetBefore"; /** - Create a [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) from the given change - description, taking the state's document length and line - separator into account. + A block widget associated with the position before it. */ - changes(spec = []) { - if (spec instanceof ChangeSet) - return spec; - return ChangeSet.of(spec, this.doc.length, this.facet(EditorState.lineSeparator)); - } + BlockType[BlockType["WidgetAfter"] = 2] = "WidgetAfter"; /** - Using the state's [line - separator](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator), create a - [`Text`](https://codemirror.net/6/docs/ref/#text.Text) instance from the given string. + A block widget [replacing](https://codemirror.net/6/docs/ref/#view.Decoration^replace) a range of content. */ - toText(string) { - return text.Text.of(string.split(this.facet(EditorState.lineSeparator) || DefaultSplit)); - } + BlockType[BlockType["WidgetRange"] = 3] = "WidgetRange"; +})(exports.BlockType || (exports.BlockType = {})); +/** +A decoration provides information on how to draw or style a piece +of content. You'll usually use it wrapped in a +[`Range`](https://codemirror.net/6/docs/ref/#rangeset.Range), which adds a start and end position. +*/ +class Decoration extends rangeset.RangeValue { /** - Return the given range of the document as a string. + @internal */ - sliceDoc(from = 0, to = this.doc.length) { - return this.doc.sliceString(from, to, this.lineBreak); - } + constructor( /** - Get the value of a state [facet](https://codemirror.net/6/docs/ref/#state.Facet). + @internal */ - facet(facet) { - let addr = this.config.address[facet.id]; - if (addr == null) - return facet.default; - ensureAddr(this, addr); - return getAddr(this, addr); - } + startSide, /** - Convert this state to a JSON-serializable object. When custom - fields should be serialized, you can pass them in as an object - mapping property names (in the resulting object, which should - not use `doc` or `selection`) to fields. + @internal */ - toJSON(fields) { - let result = { - doc: this.sliceDoc(), - selection: this.selection.toJSON() - }; - if (fields) - for (let prop in fields) { - let value = fields[prop]; - if (value instanceof StateField) - result[prop] = value.spec.toJSON(this.field(fields[prop]), this); - } - return result; - } + endSide, /** - Deserialize a state from its JSON representation. When custom - fields should be deserialized, pass the same object you passed - to [`toJSON`](https://codemirror.net/6/docs/ref/#state.EditorState.toJSON) when serializing as - third argument. + @internal */ - static fromJSON(json, config = {}, fields) { - if (!json || typeof json.doc != "string") - throw new RangeError("Invalid JSON representation for EditorState"); - let fieldInit = []; - if (fields) - for (let prop in fields) { - let field = fields[prop], value = json[prop]; - fieldInit.push(field.init(state => field.spec.fromJSON(value, state))); - } - return EditorState.create({ - doc: json.doc, - selection: EditorSelection.fromJSON(json.selection), - extensions: config.extensions ? fieldInit.concat([config.extensions]) : fieldInit - }); - } + widget, /** - Create a new state. You'll usually only need this when - initializing an editor—updated states are created by applying - transactions. + The config object used to create this decoration. You can + include additional properties in there to store metadata about + your decoration. */ - static create(config = {}) { - let { configuration, values } = Configuration.resolve(config.extensions || [], new Map); - let doc = config.doc instanceof text.Text ? config.doc - : text.Text.of((config.doc || "").split(configuration.staticFacet(EditorState.lineSeparator) || DefaultSplit)); - let selection = !config.selection ? EditorSelection.single(0) - : config.selection instanceof EditorSelection ? config.selection - : EditorSelection.single(config.selection.anchor, config.selection.head); - checkSelection(selection, doc.length); - if (!configuration.staticFacet(allowMultipleSelections)) - selection = selection.asSingle(); - return new EditorState(configuration, doc, selection, values); + spec) { + super(); + this.startSide = startSide; + this.endSide = endSide; + this.widget = widget; + this.spec = spec; } /** - The size (in columns) of a tab in the document, determined by - the [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) facet. + @internal */ - get tabSize() { return this.facet(EditorState.tabSize); } + get heightRelevant() { return false; } /** - Get the proper [line-break](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator) - string for this state. + Create a mark decoration, which influences the styling of the + content in its range. Nested mark decorations will cause nested + DOM elements to be created. Nesting order is determined by + precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) or + (below the facet-provided decorations) [view + plugin](https://codemirror.net/6/docs/ref/#view.PluginSpec.decorations). Such elements are split + on line boundaries and on the boundaries of higher-precedence + decorations. */ - get lineBreak() { return this.facet(EditorState.lineSeparator) || "\n"; } + static mark(spec) { + return new MarkDecoration(spec); + } /** - Returns true when the editor is - [configured](https://codemirror.net/6/docs/ref/#state.EditorState^readOnly) to be read-only. + Create a widget decoration, which adds an element at the given + position. */ - get readOnly() { return this.facet(readOnly); } + static widget(spec) { + let side = spec.side || 0, block = !!spec.block; + side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */); + return new PointDecoration(spec, side, side, block, spec.widget || null, false); + } /** - Look up a translation for the given phrase (via the - [`phrases`](https://codemirror.net/6/docs/ref/#state.EditorState^phrases) facet), or return the - original string if no translation is found. + Create a replace decoration which replaces the given range with + a widget, or simply hides it. */ - phrase(phrase) { - for (let map of this.facet(EditorState.phrases)) - if (Object.prototype.hasOwnProperty.call(map, phrase)) - return map[phrase]; - return phrase; + static replace(spec) { + let block = !!spec.block; + let { start, end } = getInclusive(spec, block); + let startSide = block ? (start ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 400000000 /* NonIncStart */; + let endSide = block ? (end ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -500000000 /* NonIncEnd */; + return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true); } /** - Find the values for a given language data field, provided by the - the [`languageData`](https://codemirror.net/6/docs/ref/#state.EditorState^languageData) facet. + Create a line decoration, which can add DOM attributes to the + line starting at the given position. */ - languageDataAt(name, pos, side = -1) { - let values = []; - for (let provider of this.facet(languageData)) { - for (let result of provider(this, pos, side)) { - if (Object.prototype.hasOwnProperty.call(result, name)) - values.push(result[name]); - } - } - return values; + static line(spec) { + return new LineDecoration(spec); } /** - Return a function that can categorize strings (expected to - represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak)) - into one of: - - - Word (contains an alphanumeric character or a character - explicitly listed in the local language's `"wordChars"` - language data, which should be a string) - - Space (contains only whitespace) - - Other (anything else) + Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given + decorated range or ranges. If the ranges aren't already sorted, + pass `true` for `sort` to make the library sort them for you. */ - charCategorizer(at) { - return makeCategorizer(this.languageDataAt("wordChars", at).join("")); + static set(of, sort = false) { + return rangeset.RangeSet.of(of, sort); } /** - Find the word at the given position, meaning the range - containing all [word](https://codemirror.net/6/docs/ref/#state.CharCategory.Word) characters - around it. If no word characters are adjacent to the position, - this returns null. + @internal */ - wordAt(pos) { - let { text: text$1, from, length } = this.doc.lineAt(pos); - let cat = this.charCategorizer(pos); - let start = pos - from, end = pos - from; - while (start > 0) { - let prev = text.findClusterBreak(text$1, start, false); - if (cat(text$1.slice(prev, start)) != exports.CharCategory.Word) - break; - start = prev; - } - while (end < length) { - let next = text.findClusterBreak(text$1, end); - if (cat(text$1.slice(end, next)) != exports.CharCategory.Word) - break; - end = next; - } - return start == end ? null : EditorSelection.range(start + from, end + from); - } + hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; } } /** -A facet that, when enabled, causes the editor to allow multiple -ranges to be selected. Be careful though, because by default the -editor relies on the native DOM selection, which cannot handle -multiple selections. An extension like -[`drawSelection`](https://codemirror.net/6/docs/ref/#view.drawSelection) can be used to make -secondary selections visible to the user. -*/ -EditorState.allowMultipleSelections = allowMultipleSelections; -/** -Configures the tab size to use in this state. The first -(highest-precedence) value of the facet is used. If no value is -given, this defaults to 4. -*/ -EditorState.tabSize = Facet.define({ - combine: values => values.length ? values[0] : 4 -}); -/** -The line separator to use. By default, any of `"\n"`, `"\r\n"` -and `"\r"` is treated as a separator when splitting lines, and -lines are joined with `"\n"`. - -When you configure a value here, only that precise separator -will be used, allowing you to round-trip documents through the -editor without normalizing line separators. -*/ -EditorState.lineSeparator = lineSeparator; -/** -This facet controls the value of the -[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) getter, which is -consulted by commands and extensions that implement editing -functionality to determine whether they should apply. It -defaults to false, but when its highest-precedence value is -`true`, such functionality disables itself. - -Not to be confused with -[`EditorView.editable`](https://codemirror.net/6/docs/ref/#view.EditorView^editable), which -controls whether the editor's DOM is set to be editable (and -thus focusable). -*/ -EditorState.readOnly = readOnly; -/** -Registers translation phrases. The -[`phrase`](https://codemirror.net/6/docs/ref/#state.EditorState.phrase) method will look through -all objects registered with this facet to find translations for -its argument. -*/ -EditorState.phrases = Facet.define(); -/** -A facet used to register [language -data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) providers. -*/ -EditorState.languageData = languageData; -/** -Facet used to register change filters, which are called for each -transaction (unless explicitly -[disabled](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter)), and can suppress -part of the transaction's changes. - -Such a function can return `true` to indicate that it doesn't -want to do anything, `false` to completely stop the changes in -the transaction, or a set of ranges in which changes should be -suppressed. Such ranges are represented as an array of numbers, -with each pair of two number indicating the start and end of a -range. So for example `[10, 20, 100, 110]` suppresses changes -between 10 and 20, and between 100 and 110. -*/ -EditorState.changeFilter = changeFilter; -/** -Facet used to register a hook that gets a chance to update or -replace transaction specs before they are applied. This will -only be applied for transactions that don't have -[`filter`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter) set to `false`. You -can either return a single transaction spec (possibly the input -transaction), or an array of specs (which will be combined in -the same way as the arguments to -[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update)). - -When possible, it is recommended to avoid accessing -[`Transaction.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state) in a filter, -since it will force creation of a state that will then be -discarded again, if the transaction is actually filtered. - -(This functionality should be used with care. Indiscriminately -modifying transaction is likely to break something or degrade -the user experience.) -*/ -EditorState.transactionFilter = transactionFilter; -/** -This is a more limited form of -[`transactionFilter`](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter), -which can only add -[annotations](https://codemirror.net/6/docs/ref/#state.TransactionSpec.annotations) and -[effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects). _But_, this type -of filter runs even the transaction has disabled regular -[filtering](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter), making it suitable -for effects that don't need to touch the changes or selection, -but do want to process every transaction. - -Extenders run _after_ filters, when both are applied. +The empty set of decorations. */ -EditorState.transactionExtender = transactionExtender; -Compartment.reconfigure = StateEffect.define(); +Decoration.none = rangeset.RangeSet.empty; +class MarkDecoration extends Decoration { + constructor(spec) { + let { start, end } = getInclusive(spec); + super(start ? -1 /* InlineIncStart */ : 400000000 /* NonIncStart */, end ? 1 /* InlineIncEnd */ : -500000000 /* NonIncEnd */, null, spec); + this.tagName = spec.tagName || "span"; + this.class = spec.class || ""; + this.attrs = spec.attributes || null; + } + eq(other) { + return this == other || + other instanceof MarkDecoration && + this.tagName == other.tagName && + this.class == other.class && + attrsEq(this.attrs, other.attrs); + } + range(from, to = from) { + if (from >= to) + throw new RangeError("Mark decorations may not be empty"); + return super.range(from, to); + } +} +MarkDecoration.prototype.point = false; +class LineDecoration extends Decoration { + constructor(spec) { + super(-200000000 /* Line */, -200000000 /* Line */, null, spec); + } + eq(other) { + return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes); + } + range(from, to = from) { + if (to != from) + throw new RangeError("Line decoration ranges must be zero-length"); + return super.range(from, to); + } +} +LineDecoration.prototype.mapMode = state.MapMode.TrackBefore; +LineDecoration.prototype.point = true; +class PointDecoration extends Decoration { + constructor(spec, startSide, endSide, block, widget, isReplace) { + super(startSide, endSide, widget, spec); + this.block = block; + this.isReplace = isReplace; + this.mapMode = !block ? state.MapMode.TrackDel : startSide <= 0 ? state.MapMode.TrackBefore : state.MapMode.TrackAfter; + } + // Only relevant when this.block == true + get type() { + return this.startSide < this.endSide ? exports.BlockType.WidgetRange + : this.startSide <= 0 ? exports.BlockType.WidgetBefore : exports.BlockType.WidgetAfter; + } + get heightRelevant() { return this.block || !!this.widget && this.widget.estimatedHeight >= 5; } + eq(other) { + return other instanceof PointDecoration && + widgetsEq(this.widget, other.widget) && + this.block == other.block && + this.startSide == other.startSide && this.endSide == other.endSide; + } + range(from, to = from) { + if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0))) + throw new RangeError("Invalid range for replacement decoration"); + if (!this.isReplace && to != from) + throw new RangeError("Widget decorations can only have zero-length ranges"); + return super.range(from, to); + } +} +PointDecoration.prototype.point = true; +function getInclusive(spec, block = false) { + let { inclusiveStart: start, inclusiveEnd: end } = spec; + if (start == null) + start = spec.inclusive; + if (end == null) + end = spec.inclusive; + return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block }; +} +function widgetsEq(a, b) { + return a == b || !!(a && b && a.compare(b)); +} +function addRange(from, to, ranges, margin = 0) { + let last = ranges.length - 1; + if (last >= 0 && ranges[last] + margin > from) + ranges[last] = Math.max(ranges[last], to); + else + ranges.push(from, to); +} -/** -Utility function for combining behaviors to fill in a config -object from an array of provided configs. Will, by default, error -when a field gets two values that aren't `===`-equal, but you can -provide combine functions per field to do something else. -*/ -function combineConfig(configs, defaults, // Should hold only the optional properties of Config, but I haven't managed to express that -combine = {}) { - let result = {}; - for (let config of configs) - for (let key of Object.keys(config)) { - let value = config[key], current = result[key]; - if (current === undefined) - result[key] = value; - else if (current === value || value === undefined) ; // No conflict - else if (Object.hasOwnProperty.call(combine, key)) - result[key] = combine[key](current, value); - else - throw new Error("Config merge conflict for field " + key); +class LineView extends ContentView { + constructor() { + super(...arguments); + this.children = []; + this.length = 0; + this.prevAttrs = undefined; + this.attrs = null; + this.breakAfter = 0; + } + // Consumes source + merge(from, to, source, hasStart, openStart, openEnd) { + if (source) { + if (!(source instanceof LineView)) + return false; + if (!this.dom) + source.transferDOM(this); // Reuse source.dom when appropriate + } + if (hasStart) + this.setDeco(source ? source.attrs : null); + mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd); + return true; + } + split(at) { + let end = new LineView; + end.breakAfter = this.breakAfter; + if (this.length == 0) + return end; + let { i, off } = this.childPos(at); + if (off) { + end.append(this.children[i].split(off), 0); + this.children[i].merge(off, this.children[i].length, null, false, 0, 0); + i++; + } + for (let j = i; j < this.children.length; j++) + end.append(this.children[j], 0); + while (i > 0 && this.children[i - 1].length == 0) + this.children[--i].destroy(); + this.children.length = i; + this.markDirty(); + this.length = at; + return end; + } + transferDOM(other) { + if (!this.dom) + return; + other.setDOM(this.dom); + other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs; + this.prevAttrs = undefined; + this.dom = null; + } + setDeco(attrs) { + if (!attrsEq(this.attrs, attrs)) { + if (this.dom) { + this.prevAttrs = this.attrs; + this.markDirty(); + } + this.attrs = attrs; + } + } + append(child, openStart) { + joinInlineInto(this, child, openStart); + } + // Only called when building a line view in ContentBuilder + addLineDeco(deco) { + let attrs = deco.spec.attributes, cls = deco.spec.class; + if (attrs) + this.attrs = combineAttrs(attrs, this.attrs || {}); + if (cls) + this.attrs = combineAttrs({ class: cls }, this.attrs || {}); + } + domAtPos(pos) { + return inlineDOMAtPos(this.dom, this.children, pos); + } + reuseDOM(node) { + if (node.nodeName == "DIV") { + this.setDOM(node); + this.dirty |= 4 /* Attrs */ | 2 /* Node */; + } + } + sync(track) { + var _a; + if (!this.dom) { + this.setDOM(document.createElement("div")); + this.dom.className = "cm-line"; + this.prevAttrs = this.attrs ? null : undefined; + } + else if (this.dirty & 4 /* Attrs */) { + clearAttributes(this.dom); + this.dom.className = "cm-line"; + this.prevAttrs = this.attrs ? null : undefined; + } + if (this.prevAttrs !== undefined) { + updateAttrs(this.dom, this.prevAttrs, this.attrs); + this.dom.classList.add("cm-line"); + this.prevAttrs = undefined; + } + super.sync(track); + let last = this.dom.lastChild; + while (last && ContentView.get(last) instanceof MarkView) + last = last.lastChild; + if (!last || + last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false && + (!browser.ios || !this.children.some(ch => ch instanceof TextView))) { + let hack = document.createElement("BR"); + hack.cmIgnore = true; + this.dom.appendChild(hack); + } + } + measureTextSize() { + if (this.children.length == 0 || this.length > 20) + return null; + let totalWidth = 0; + for (let child of this.children) { + if (!(child instanceof TextView)) + return null; + let rects = clientRectsFor(child.dom); + if (rects.length != 1) + return null; + totalWidth += rects[0].width; + } + return { lineHeight: this.dom.getBoundingClientRect().height, + charWidth: totalWidth / this.length }; + } + coordsAt(pos, side) { + return coordsInChildren(this, pos, side); + } + become(_other) { return false; } + get type() { return exports.BlockType.Text; } + static find(docView, pos) { + for (let i = 0, off = 0; i < docView.children.length; i++) { + let block = docView.children[i], end = off + block.length; + if (end >= pos) { + if (block instanceof LineView) + return block; + if (end > pos) + break; + } + off = end + block.breakAfter; } - for (let key in defaults) - if (result[key] === undefined) - result[key] = defaults[key]; - return result; -} - -Object.defineProperty(exports, 'Text', { - enumerable: true, - get: function () { - return text.Text; + return null; } -}); -exports.Annotation = Annotation; -exports.AnnotationType = AnnotationType; -exports.ChangeDesc = ChangeDesc; -exports.ChangeSet = ChangeSet; -exports.Compartment = Compartment; -exports.EditorSelection = EditorSelection; -exports.EditorState = EditorState; -exports.Facet = Facet; -exports.Prec = Prec; -exports.SelectionRange = SelectionRange; -exports.StateEffect = StateEffect; -exports.StateEffectType = StateEffectType; -exports.StateField = StateField; -exports.Transaction = Transaction; -exports.combineConfig = combineConfig; - -},{"@codemirror/text":52}],52:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -// Compressed representation of the Grapheme_Cluster_Break=Extend -// information from -// http://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakProperty.txt. -// Each pair of elements represents a range, as an offet from the -// previous range and a length. Numbers are in base-36, with the empty -// string being a shorthand for 1. -let extend = "lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(s => s ? parseInt(s, 36) : 1); -// Convert offsets into absolute values -for (let i = 1; i < extend.length; i++) - extend[i] += extend[i - 1]; -function isExtendingChar(code) { - for (let i = 1; i < extend.length; i += 2) - if (extend[i] > code) - return extend[i - 1] <= code; - return false; -} -function isRegionalIndicator(code) { - return code >= 0x1F1E6 && code <= 0x1F1FF; } -const ZWJ = 0x200d; -/** -Returns a next grapheme cluster break _after_ (not equal to) -`pos`, if `forward` is true, or before otherwise. Returns `pos` -itself if no further cluster break is available in the string. -Moves across surrogate pairs, extending characters (when -`includeExtending` is true), characters joined with zero-width -joiners, and flag emoji. -*/ -function findClusterBreak(str, pos, forward = true, includeExtending = true) { - return (forward ? nextClusterBreak : prevClusterBreak)(str, pos, includeExtending); +class BlockWidgetView extends ContentView { + constructor(widget, length, type) { + super(); + this.widget = widget; + this.length = length; + this.type = type; + this.breakAfter = 0; + } + merge(from, to, source, _takeDeco, openStart, openEnd) { + if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) || + from > 0 && openStart <= 0 || to < this.length && openEnd <= 0)) + return false; + this.length = from + (source ? source.length : 0) + (this.length - to); + return true; + } + domAtPos(pos) { + return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length); + } + split(at) { + let len = this.length - at; + this.length = at; + let end = new BlockWidgetView(this.widget, len, this.type); + end.breakAfter = this.breakAfter; + return end; + } + get children() { return noChildren; } + sync() { + if (!this.dom || !this.widget.updateDOM(this.dom)) { + this.setDOM(this.widget.toDOM(this.editorView)); + this.dom.contentEditable = "false"; + } + } + get overrideDOMText() { + return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : state.Text.empty; + } + domBoundsAround() { return null; } + become(other) { + if (other instanceof BlockWidgetView && other.type == this.type && + other.widget.constructor == this.widget.constructor) { + if (!other.widget.eq(this.widget)) + this.markDirty(true); + this.widget = other.widget; + this.length = other.length; + this.breakAfter = other.breakAfter; + return true; + } + return false; + } + ignoreMutation() { return true; } + ignoreEvent(event) { return this.widget.ignoreEvent(event); } + destroy() { + super.destroy(); + if (this.dom) + this.widget.destroy(this.dom); + } } -function nextClusterBreak(str, pos, includeExtending) { - if (pos == str.length) - return pos; - // If pos is in the middle of a surrogate pair, move to its start - if (pos && surrogateLow(str.charCodeAt(pos)) && surrogateHigh(str.charCodeAt(pos - 1))) - pos--; - let prev = codePointAt(str, pos); - pos += codePointSize(prev); - while (pos < str.length) { - let next = codePointAt(str, pos); - if (prev == ZWJ || next == ZWJ || includeExtending && isExtendingChar(next)) { - pos += codePointSize(next); - prev = next; + +class ContentBuilder { + constructor(doc, pos, end, disallowBlockEffectsBelow) { + this.doc = doc; + this.pos = pos; + this.end = end; + this.disallowBlockEffectsBelow = disallowBlockEffectsBelow; + this.content = []; + this.curLine = null; + this.breakAtStart = 0; + this.pendingBuffer = 0 /* No */; + // Set to false directly after a widget that covers the position after it + this.atCursorPos = true; + this.openStart = -1; + this.openEnd = -1; + this.text = ""; + this.textOff = 0; + this.cursor = doc.iter(); + this.skip = pos; + } + posCovered() { + if (this.content.length == 0) + return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos; + let last = this.content[this.content.length - 1]; + return !last.breakAfter && !(last instanceof BlockWidgetView && last.type == exports.BlockType.WidgetBefore); + } + getLine() { + if (!this.curLine) { + this.content.push(this.curLine = new LineView); + this.atCursorPos = true; } - else if (isRegionalIndicator(next)) { - let countBefore = 0, i = pos - 2; - while (i >= 0 && isRegionalIndicator(codePointAt(str, i))) { - countBefore++; - i -= 2; + return this.curLine; + } + flushBuffer(active) { + if (this.pendingBuffer) { + this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length); + this.pendingBuffer = 0 /* No */; + } + } + addBlockWidget(view) { + this.flushBuffer([]); + this.curLine = null; + this.content.push(view); + } + finish(openEnd) { + if (!openEnd) + this.flushBuffer([]); + else + this.pendingBuffer = 0 /* No */; + if (!this.posCovered()) + this.getLine(); + } + buildText(length, active, openStart) { + while (length > 0) { + if (this.textOff == this.text.length) { + let { value, lineBreak, done } = this.cursor.next(this.skip); + this.skip = 0; + if (done) + throw new Error("Ran out of text content when drawing inline views"); + if (lineBreak) { + if (!this.posCovered()) + this.getLine(); + if (this.content.length) + this.content[this.content.length - 1].breakAfter = 1; + else + this.breakAtStart = 1; + this.flushBuffer([]); + this.curLine = null; + length--; + continue; + } + else { + this.text = value; + this.textOff = 0; + } } - if (countBefore % 2 == 0) - break; - else - pos += 2; + let take = Math.min(this.text.length - this.textOff, length, 512 /* Chunk */); + this.flushBuffer(active); + this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart); + this.atCursorPos = true; + this.textOff += take; + length -= take; + openStart = 0; } - else { - break; + } + span(from, to, active, openStart) { + this.buildText(to - from, active, openStart); + this.pos = to; + if (this.openStart < 0) + this.openStart = openStart; + } + point(from, to, deco, active, openStart) { + let len = to - from; + if (deco instanceof PointDecoration) { + if (deco.block) { + let { type } = deco; + if (type == exports.BlockType.WidgetAfter && !this.posCovered()) + this.getLine(); + this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type)); + } + else { + let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide); + let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0); + let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0); + let line = this.getLine(); + if (this.pendingBuffer == 2 /* IfCursor */ && !cursorBefore) + this.pendingBuffer = 0 /* No */; + this.flushBuffer(active); + if (cursorBefore) { + line.append(wrapMarks(new WidgetBufferView(1), active), openStart); + openStart = active.length + Math.max(0, openStart - active.length); + } + line.append(wrapMarks(view, active), openStart); + this.atCursorPos = cursorAfter; + this.pendingBuffer = !cursorAfter ? 0 /* No */ : from < to ? 1 /* Yes */ : 2 /* IfCursor */; + } + } + else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration + this.getLine().addLineDeco(deco); + } + if (len) { + // Advance the iterator past the replaced content + if (this.textOff + len <= this.text.length) { + this.textOff += len; + } + else { + this.skip += len - (this.text.length - this.textOff); + this.text = ""; + this.textOff = 0; + } + this.pos = to; } + if (this.openStart < 0) + this.openStart = openStart; } - return pos; -} -function prevClusterBreak(str, pos, includeExtending) { - while (pos > 0) { - let found = nextClusterBreak(str, pos - 2, includeExtending); - if (found < pos) - return found; - pos--; + filterPoint(from, to, value, index) { + if (index >= this.disallowBlockEffectsBelow || !(value instanceof PointDecoration)) + return true; + if (value.block) + throw new RangeError("Block decorations may not be specified via plugins"); + return to <= this.doc.lineAt(this.pos).to; + } + static build(text, from, to, decorations, pluginDecorationLength) { + let builder = new ContentBuilder(text, from, to, pluginDecorationLength); + builder.openEnd = rangeset.RangeSet.spans(decorations, from, to, builder); + if (builder.openStart < 0) + builder.openStart = builder.openEnd; + builder.finish(builder.openEnd); + return builder; } - return 0; } -function surrogateLow(ch) { return ch >= 0xDC00 && ch < 0xE000; } -function surrogateHigh(ch) { return ch >= 0xD800 && ch < 0xDC00; } -/** -Find the code point at the given position in a string (like the -[`codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) -string method). -*/ -function codePointAt(str, pos) { - let code0 = str.charCodeAt(pos); - if (!surrogateHigh(code0) || pos + 1 == str.length) - return code0; - let code1 = str.charCodeAt(pos + 1); - if (!surrogateLow(code1)) - return code0; - return ((code0 - 0xd800) << 10) + (code1 - 0xdc00) + 0x10000; +function wrapMarks(view, active) { + for (let mark of active) + view = new MarkView(mark, [view], view.length); + return view; } -/** -Given a Unicode codepoint, return the JavaScript string that -respresents it (like -[`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint)). -*/ -function fromCodePoint(code) { - if (code <= 0xffff) - return String.fromCharCode(code); - code -= 0x10000; - return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00); +class NullWidget extends WidgetType { + constructor(tag) { + super(); + this.tag = tag; + } + eq(other) { return other.tag == this.tag; } + toDOM() { return document.createElement(this.tag); } + updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; } } -/** -The first character that takes up two positions in a JavaScript -string. It is often useful to compare with this after calling -`codePointAt`, to figure out whether your character takes up 1 or -2 index positions. -*/ -function codePointSize(code) { return code < 0x10000 ? 1 : 2; } -/** -Count the column position at the given offset into the string, -taking extending characters and tab size into account. -*/ -function countColumn(string, tabSize, to = string.length) { - let n = 0; - for (let i = 0; i < to;) { - if (string.charCodeAt(i) == 9) { - n += tabSize - (n % tabSize); - i++; - } - else { - n++; - i = findClusterBreak(string, i); - } +const none = []; +const clickAddsSelectionRange = state.Facet.define(); +const dragMovesSelection$1 = state.Facet.define(); +const mouseSelectionStyle = state.Facet.define(); +const exceptionSink = state.Facet.define(); +const updateListener = state.Facet.define(); +const inputHandler = state.Facet.define(); +// FIXME remove +const scrollTo = state.StateEffect.define({ + map: (range, changes) => range.map(changes) +}); +// FIXME remove +const centerOn = state.StateEffect.define({ + map: (range, changes) => range.map(changes) +}); +class ScrollTarget { + constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) { + this.range = range; + this.y = y; + this.x = x; + this.yMargin = yMargin; + this.xMargin = xMargin; + } + map(changes) { + return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin); } - return n; } +const scrollIntoView = state.StateEffect.define({ map: (t, ch) => t.map(ch) }); /** -Find the offset that corresponds to the given column position in a -string, taking extending characters and tab size into account. By -default, the string length is returned when it is too short to -reach the column. Pass `strict` true to make it return -1 in that -situation. +Log or report an unhandled exception in client code. Should +probably only be used by extension code that allows client code to +provide functions, and calls those functions in a context where an +exception can't be propagated to calling code in a reasonable way +(for example when in an event handler). + +Either calls a handler registered with +[`EditorView.exceptionSink`](https://codemirror.net/6/docs/ref/#view.EditorView^exceptionSink), +`window.onerror`, if defined, or `console.error` (in which case +it'll pass `context`, when given, as first argument). */ -function findColumn(string, col, tabSize, strict) { - for (let i = 0, n = 0;;) { - if (n >= col) - return i; - if (i == string.length) - break; - n += string.charCodeAt(i) == 9 ? tabSize - (n % tabSize) : 1; - i = findClusterBreak(string, i); - } - return strict === true ? -1 : string.length; +function logException(state, exception, context) { + let handler = state.facet(exceptionSink); + if (handler.length) + handler[0](exception); + else if (window.onerror) + window.onerror(String(exception), context, undefined, undefined, exception); + else if (context) + console.error(context + ":", exception); + else + console.error(exception); } - +const editable = state.Facet.define({ combine: values => values.length ? values[0] : true }); /** -The data structure for documents. +Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which +[fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin) +provides. */ -class Text { +class PluginFieldProvider { /** @internal */ - constructor() { } - /** - Get the line description around the given position. - */ - lineAt(pos) { - if (pos < 0 || pos > this.length) - throw new RangeError(`Invalid position ${pos} in document of length ${this.length}`); - return this.lineInner(pos, false, 1, 0); - } - /** - Get the description for the given (1-based) line number. - */ - line(n) { - if (n < 1 || n > this.lines) - throw new RangeError(`Invalid line number ${n} in ${this.lines}-line document`); - return this.lineInner(n, true, 1, 0); - } - /** - Replace a range of the text with the given content. - */ - replace(from, to, text) { - let parts = []; - this.decompose(0, from, parts, 2 /* To */); - if (text.length) - text.decompose(0, text.length, parts, 1 /* From */ | 2 /* To */); - this.decompose(to, this.length, parts, 1 /* From */); - return TextNode.from(parts, this.length - (to - from) + text.length); - } + constructor( /** - Append another document to this one. + @internal */ - append(other) { - return this.replace(this.length, this.length, other); - } + field, /** - Retrieve the text between the given points. + @internal */ - slice(from, to = this.length) { - let parts = []; - this.decompose(from, to, parts, 0); - return TextNode.from(parts, to - from); + get) { + this.field = field; + this.get = get; } +} +/** +Plugin fields are a mechanism for allowing plugins to provide +values that can be retrieved through the +[`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method. +*/ +class PluginField { /** - Test whether this text is equal to another instance. + Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field, + to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) + option. */ - eq(other) { - if (other == this) - return true; - if (other.length != this.length || other.lines != this.lines) - return false; - let start = this.scanIdentical(other, 1), end = this.length - this.scanIdentical(other, -1); - let a = new RawTextCursor(this), b = new RawTextCursor(other); - for (let skip = start, pos = start;;) { - a.next(skip); - b.next(skip); - skip = 0; - if (a.lineBreak != b.lineBreak || a.done != b.done || a.value != b.value) - return false; - pos += a.value.length; - if (a.done || pos >= end) - return true; - } + from(get) { + return new PluginFieldProvider(this, get); } /** - Iterate over the text. When `dir` is `-1`, iteration happens - from end to start. This will return lines and the breaks between - them as separate strings, and for long lines, might split lines - themselves into multiple chunks as well. + Define a new plugin field. */ - iter(dir = 1) { return new RawTextCursor(this, dir); } + static define() { return new PluginField(); } +} +/** +This field can be used by plugins to provide +[decorations](https://codemirror.net/6/docs/ref/#view.Decoration). + +**Note**: For reasons of data flow (plugins are only updated +after the viewport is computed), decorations produced by plugins +are _not_ taken into account when predicting the vertical layout +structure of the editor. They **must not** introduce block +widgets (that will raise an error) or replacing decorations that +cover line breaks (these will be ignored if they occur). Such +decorations, or others that cause a large amount of vertical +size shift compared to the undecorated content, should be +provided through the state-level [`decorations` +facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead. +*/ +PluginField.decorations = PluginField.define(); +/** +Used to provide ranges that should be treated as atoms as far as +cursor motion is concerned. This causes methods like +[`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and +[`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the +commands built on top of them) to skip across such regions when +a selection endpoint would enter them. This does _not_ prevent +direct programmatic [selection +updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such +regions. +*/ +PluginField.atomicRanges = PluginField.define(); +/** +Plugins can provide additional scroll margins (space around the +sides of the scrolling element that should be considered +invisible) through this field. This can be useful when the +plugin introduces elements that cover part of that element (for +example a horizontally fixed gutter). +*/ +PluginField.scrollMargins = PluginField.define(); +let nextPluginID = 0; +const viewPlugin = state.Facet.define(); +/** +View plugins associate stateful values with a view. They can +influence the way the content is drawn, and are notified of things +that happen in the view. +*/ +class ViewPlugin { + constructor( /** - Iterate over a range of the text. When `from` > `to`, the - iterator will run in reverse. + @internal */ - iterRange(from, to = this.length) { return new PartialTextCursor(this, from, to); } + id, /** - Return a cursor that iterates over the given range of lines, - _without_ returning the line breaks between, and yielding empty - strings for empty lines. - - When `from` and `to` are given, they should be 1-based line numbers. + @internal */ - iterLines(from, to) { - let inner; - if (from == null) { - inner = this.iter(); - } - else { - if (to == null) - to = this.lines + 1; - let start = this.line(from).from; - inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to)); - } - return new LineCursor(inner); - } + create, /** @internal */ - toString() { return this.sliceString(0); } + fields) { + this.id = id; + this.create = create; + this.fields = fields; + this.extension = viewPlugin.of(this); + } /** - Convert the document to an array of lines (which can be - deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#text.Text^of)). + Define a plugin from a constructor function that creates the + plugin's value, given an editor view. */ - toJSON() { - let lines = []; - this.flatten(lines); - return lines; + static define(create, spec) { + let { eventHandlers, provide, decorations } = spec || {}; + let fields = []; + if (provide) + for (let provider of Array.isArray(provide) ? provide : [provide]) + fields.push(provider); + if (eventHandlers) + fields.push(domEventHandlers.from((value) => ({ plugin: value, handlers: eventHandlers }))); + if (decorations) + fields.push(PluginField.decorations.from(decorations)); + return new ViewPlugin(nextPluginID++, create, fields); } /** - Create a `Text` instance for the given array of lines. + Create a plugin for a class whose constructor takes a single + editor view as argument. */ - static of(text) { - if (text.length == 0) - throw new RangeError("A document must have at least one line"); - if (text.length == 1 && !text[0]) - return Text.empty; - return text.length <= 32 /* Branch */ ? new TextLeaf(text) : TextNode.from(TextLeaf.split(text, [])); + static fromClass(cls, spec) { + return ViewPlugin.define(view => new cls(view), spec); } } -// Leaves store an array of line strings. There are always line breaks -// between these strings. Leaves are limited in size and have to be -// contained in TextNode instances for bigger documents. -class TextLeaf extends Text { - constructor(text, length = textLength(text)) { - super(); - this.text = text; - this.length = length; +const domEventHandlers = PluginField.define(); +class PluginInstance { + constructor(spec) { + this.spec = spec; + // When starting an update, all plugins have this field set to the + // update object, indicating they need to be updated. When finished + // updating, it is set to `false`. Retrieving a plugin that needs to + // be updated with `view.plugin` forces an eager update. + this.mustUpdate = null; + // This is null when the plugin is initially created, but + // initialized on the first update. + this.value = null; } - get lines() { return this.text.length; } - get children() { return null; } - lineInner(target, isLine, line, offset) { - for (let i = 0;; i++) { - let string = this.text[i], end = offset + string.length; - if ((isLine ? line : end) >= target) - return new Line(offset, end, line, string); - offset = end + 1; - line++; - } + takeField(type, target) { + if (this.spec) + for (let { field, get } of this.spec.fields) + if (field == type) + target.push(get(this.value)); } - decompose(from, to, target, open) { - let text = from <= 0 && to >= this.length ? this - : new TextLeaf(sliceText(this.text, from, to), Math.min(to, this.length) - Math.max(0, from)); - if (open & 1 /* From */) { - let prev = target.pop(); - let joined = appendText(text.text, prev.text.slice(), 0, text.length); - if (joined.length <= 32 /* Branch */) { - target.push(new TextLeaf(joined, prev.length + text.length)); - } - else { - let mid = joined.length >> 1; - target.push(new TextLeaf(joined.slice(0, mid)), new TextLeaf(joined.slice(mid))); + update(view) { + if (!this.value) { + if (this.spec) { + try { + this.value = this.spec.create(view); + } + catch (e) { + logException(view.state, e, "CodeMirror plugin crashed"); + this.deactivate(); + } } } - else { - target.push(text); - } - } - replace(from, to, text) { - if (!(text instanceof TextLeaf)) - return super.replace(from, to, text); - let lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to); - let newLen = this.length + text.length - (to - from); - if (lines.length <= 32 /* Branch */) - return new TextLeaf(lines, newLen); - return TextNode.from(TextLeaf.split(lines, []), newLen); - } - sliceString(from, to = this.length, lineSep = "\n") { - let result = ""; - for (let pos = 0, i = 0; pos <= to && i < this.text.length; i++) { - let line = this.text[i], end = pos + line.length; - if (pos > from && i) - result += lineSep; - if (from < end && to > pos) - result += line.slice(Math.max(0, from - pos), to - pos); - pos = end + 1; - } - return result; - } - flatten(target) { - for (let line of this.text) - target.push(line); - } - scanIdentical() { return 0; } - static split(text, target) { - let part = [], len = -1; - for (let line of text) { - part.push(line); - len += line.length + 1; - if (part.length == 32 /* Branch */) { - target.push(new TextLeaf(part, len)); - part = []; - len = -1; + else if (this.mustUpdate) { + let update = this.mustUpdate; + this.mustUpdate = null; + if (this.value.update) { + try { + this.value.update(update); + } + catch (e) { + logException(update.state, e, "CodeMirror plugin crashed"); + if (this.value.destroy) + try { + this.value.destroy(); + } + catch (_) { } + this.deactivate(); + } } } - if (len > -1) - target.push(new TextLeaf(part, len)); - return target; - } -} -// Nodes provide the tree structure of the `Text` type. They store a -// number of other nodes or leaves, taking care to balance themselves -// on changes. There are implied line breaks _between_ the children of -// a node (but not before the first or after the last child). -class TextNode extends Text { - constructor(children, length) { - super(); - this.children = children; - this.length = length; - this.lines = 0; - for (let child of children) - this.lines += child.lines; - } - lineInner(target, isLine, line, offset) { - for (let i = 0;; i++) { - let child = this.children[i], end = offset + child.length, endLine = line + child.lines - 1; - if ((isLine ? endLine : end) >= target) - return child.lineInner(target, isLine, line, offset); - offset = end + 1; - line = endLine + 1; - } + return this; } - decompose(from, to, target, open) { - for (let i = 0, pos = 0; pos <= to && i < this.children.length; i++) { - let child = this.children[i], end = pos + child.length; - if (from <= end && to >= pos) { - let childOpen = open & ((pos <= from ? 1 /* From */ : 0) | (end >= to ? 2 /* To */ : 0)); - if (pos >= from && end <= to && !childOpen) - target.push(child); - else - child.decompose(from - pos, to - pos, target, childOpen); + destroy(view) { + var _a; + if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.destroy) { + try { + this.value.destroy(); } - pos = end + 1; - } - } - replace(from, to, text) { - if (text.lines < this.lines) - for (let i = 0, pos = 0; i < this.children.length; i++) { - let child = this.children[i], end = pos + child.length; - // Fast path: if the change only affects one child and the - // child's size remains in the acceptable range, only update - // that child - if (from >= pos && to <= end) { - let updated = child.replace(from - pos, to - pos, text); - let totalLines = this.lines - child.lines + updated.lines; - if (updated.lines < (totalLines >> (5 /* BranchShift */ - 1)) && - updated.lines > (totalLines >> (5 /* BranchShift */ + 1))) { - let copy = this.children.slice(); - copy[i] = updated; - return new TextNode(copy, this.length - (to - from) + text.length); - } - return super.replace(pos, end, updated); - } - pos = end + 1; + catch (e) { + logException(view.state, e, "CodeMirror plugin crashed"); } - return super.replace(from, to, text); - } - sliceString(from, to = this.length, lineSep = "\n") { - let result = ""; - for (let i = 0, pos = 0; i < this.children.length && pos <= to; i++) { - let child = this.children[i], end = pos + child.length; - if (pos > from && i) - result += lineSep; - if (from < end && to > pos) - result += child.sliceString(from - pos, to - pos, lineSep); - pos = end + 1; } - return result; } - flatten(target) { - for (let child of this.children) - child.flatten(target); + deactivate() { + this.spec = this.value = null; } - scanIdentical(other, dir) { - if (!(other instanceof TextNode)) - return 0; - let length = 0; - let [iA, iB, eA, eB] = dir > 0 ? [0, 0, this.children.length, other.children.length] - : [this.children.length - 1, other.children.length - 1, -1, -1]; - for (;; iA += dir, iB += dir) { - if (iA == eA || iB == eB) - return length; - let chA = this.children[iA], chB = other.children[iB]; - if (chA != chB) - return length + chA.scanIdentical(chB, dir); - length += chA.length + 1; - } +} +const editorAttributes = state.Facet.define(); +const contentAttributes = state.Facet.define(); +// Provide decorations +const decorations = state.Facet.define(); +const styleModule = state.Facet.define(); +class ChangedRange { + constructor(fromA, toA, fromB, toB) { + this.fromA = fromA; + this.toA = toA; + this.fromB = fromB; + this.toB = toB; } - static from(children, length = children.reduce((l, ch) => l + ch.length + 1, -1)) { - let lines = 0; - for (let ch of children) - lines += ch.lines; - if (lines < 32 /* Branch */) { - let flat = []; - for (let ch of children) - ch.flatten(flat); - return new TextLeaf(flat, length); - } - let chunk = Math.max(32 /* Branch */, lines >> 5 /* BranchShift */), maxChunk = chunk << 1, minChunk = chunk >> 1; - let chunked = [], currentLines = 0, currentLen = -1, currentChunk = []; - function add(child) { - let last; - if (child.lines > maxChunk && child instanceof TextNode) { - for (let node of child.children) - add(node); - } - else if (child.lines > minChunk && (currentLines > minChunk || !currentLines)) { - flush(); - chunked.push(child); - } - else if (child instanceof TextLeaf && currentLines && - (last = currentChunk[currentChunk.length - 1]) instanceof TextLeaf && - child.lines + last.lines <= 32 /* Branch */) { - currentLines += child.lines; - currentLen += child.length + 1; - currentChunk[currentChunk.length - 1] = new TextLeaf(last.text.concat(child.text), last.length + 1 + child.length); - } - else { - if (currentLines + child.lines > chunk) - flush(); - currentLines += child.lines; - currentLen += child.length + 1; - currentChunk.push(child); - } - } - function flush() { - if (currentLines == 0) - return; - chunked.push(currentChunk.length == 1 ? currentChunk[0] : TextNode.from(currentChunk, currentLen)); - currentLen = -1; - currentLines = currentChunk.length = 0; + join(other) { + return new ChangedRange(Math.min(this.fromA, other.fromA), Math.max(this.toA, other.toA), Math.min(this.fromB, other.fromB), Math.max(this.toB, other.toB)); + } + addToSet(set) { + let i = set.length, me = this; + for (; i > 0; i--) { + let range = set[i - 1]; + if (range.fromA > me.toA) + continue; + if (range.toA < me.fromA) + break; + me = me.join(range); + set.splice(i - 1, 1); } - for (let child of children) - add(child); - flush(); - return chunked.length == 1 ? chunked[0] : new TextNode(chunked, length); + set.splice(i, 0, me); + return set; } -} -Text.empty = new TextLeaf([""], 0); -function textLength(text) { - let length = -1; - for (let line of text) - length += line.length + 1; - return length; -} -function appendText(text, target, from = 0, to = 1e9) { - for (let pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) { - let line = text[i], end = pos + line.length; - if (end >= from) { - if (end > to) - line = line.slice(0, to - pos); - if (pos < from) - line = line.slice(from - pos); - if (first) { - target[target.length - 1] += line; - first = false; + static extendWithRanges(diff, ranges) { + if (ranges.length == 0) + return diff; + let result = []; + for (let dI = 0, rI = 0, posA = 0, posB = 0;; dI++) { + let next = dI == diff.length ? null : diff[dI], off = posA - posB; + let end = next ? next.fromB : 1e9; + while (rI < ranges.length && ranges[rI] < end) { + let from = ranges[rI], to = ranges[rI + 1]; + let fromB = Math.max(posB, from), toB = Math.min(end, to); + if (fromB <= toB) + new ChangedRange(fromB + off, toB + off, fromB, toB).addToSet(result); + if (to > end) + break; + else + rI += 2; } - else - target.push(line); + if (!next) + return result; + new ChangedRange(next.fromA, next.toA, next.fromB, next.toB).addToSet(result); + posA = next.toA; + posB = next.toB; } - pos = end + 1; } - return target; } -function sliceText(text, from, to) { - return appendText(text, [""], from, to); -} -class RawTextCursor { - constructor(text, dir = 1) { - this.dir = dir; - this.done = false; - this.lineBreak = false; - this.value = ""; - this.nodes = [text]; - this.offsets = [dir > 0 ? 1 : (text instanceof TextLeaf ? text.text.length : text.children.length) << 1]; - } - nextInner(skip, dir) { - this.done = this.lineBreak = false; - for (;;) { - let last = this.nodes.length - 1; - let top = this.nodes[last], offsetValue = this.offsets[last], offset = offsetValue >> 1; - let size = top instanceof TextLeaf ? top.text.length : top.children.length; - if (offset == (dir > 0 ? size : 0)) { - if (last == 0) { - this.done = true; - this.value = ""; - return this; - } - if (dir > 0) - this.offsets[last - 1]++; - this.nodes.pop(); - this.offsets.pop(); - } - else if ((offsetValue & 1) == (dir > 0 ? 0 : 1)) { - this.offsets[last] += dir; - if (skip == 0) { - this.lineBreak = true; - this.value = "\n"; - return this; - } - skip--; - } - else if (top instanceof TextLeaf) { - // Move to the next string - let next = top.text[offset + (dir < 0 ? -1 : 0)]; - this.offsets[last] += dir; - if (next.length > Math.max(0, skip)) { - this.value = skip == 0 ? next : dir > 0 ? next.slice(skip) : next.slice(0, next.length - skip); - return this; - } - skip -= next.length; - } - else { - let next = top.children[offset + (dir < 0 ? -1 : 0)]; - if (skip > next.length) { - skip -= next.length; - this.offsets[last] += dir; - } - else { - if (dir < 0) - this.offsets[last]--; - this.nodes.push(next); - this.offsets.push(dir > 0 ? 1 : (next instanceof TextLeaf ? next.text.length : next.children.length) << 1); - } - } +/** +View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this +class, which describe what happened, whenever the view is updated. +*/ +class ViewUpdate { + /** + @internal + */ + constructor( + /** + The editor view that the update is associated with. + */ + view, + /** + The new editor state. + */ + state$1, + /** + The transactions involved in the update. May be empty. + */ + transactions = none) { + this.view = view; + this.state = state$1; + this.transactions = transactions; + /** + @internal + */ + this.flags = 0; + this.startState = view.state; + this.changes = state.ChangeSet.empty(this.startState.doc.length); + for (let tr of transactions) + this.changes = this.changes.compose(tr.changes); + let changedRanges = []; + this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB))); + this.changedRanges = changedRanges; + let focus = view.hasFocus; + if (focus != view.inputState.notifiedFocused) { + view.inputState.notifiedFocused = focus; + this.flags |= 1 /* Focus */; } } - next(skip = 0) { - if (skip < 0) { - this.nextInner(-skip, (-this.dir)); - skip = this.value.length; - } - return this.nextInner(skip, this.dir); + /** + Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or + [visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this + update. + */ + get viewportChanged() { + return (this.flags & 4 /* Viewport */) > 0; } -} -class PartialTextCursor { - constructor(text, start, end) { - this.value = ""; - this.done = false; - this.cursor = new RawTextCursor(text, start > end ? -1 : 1); - this.pos = start > end ? text.length : 0; - this.from = Math.min(start, end); - this.to = Math.max(start, end); + /** + Indicates whether the height of an element in the editor changed + in this update. + */ + get heightChanged() { + return (this.flags & 2 /* Height */) > 0; } - nextInner(skip, dir) { - if (dir < 0 ? this.pos <= this.from : this.pos >= this.to) { - this.value = ""; - this.done = true; - return this; - } - skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos); - let limit = dir < 0 ? this.pos - this.from : this.to - this.pos; - if (skip > limit) - skip = limit; - limit -= skip; - let { value } = this.cursor.next(skip); - this.pos += (value.length + skip) * dir; - this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit); - this.done = !this.value; - return this; + /** + Returns true when the document was modified or the size of the + editor, or elements within the editor, changed. + */ + get geometryChanged() { + return this.docChanged || (this.flags & (8 /* Geometry */ | 2 /* Height */)) > 0; } - next(skip = 0) { - if (skip < 0) - skip = Math.max(skip, this.from - this.pos); - else if (skip > 0) - skip = Math.min(skip, this.to - this.pos); - return this.nextInner(skip, this.cursor.dir); + /** + True when this update indicates a focus change. + */ + get focusChanged() { + return (this.flags & 1 /* Focus */) > 0; } - get lineBreak() { return this.cursor.lineBreak && this.value != ""; } -} -class LineCursor { - constructor(inner) { - this.inner = inner; - this.afterBreak = true; - this.value = ""; - this.done = false; + /** + Whether the document changed in this update. + */ + get docChanged() { + return !this.changes.empty; } - next(skip = 0) { - let { done, lineBreak, value } = this.inner.next(skip); - if (done) { - this.done = true; - this.value = ""; - } - else if (lineBreak) { - if (this.afterBreak) { - this.value = ""; - } - else { - this.afterBreak = true; - this.next(); - } - } - else { - this.value = value; - this.afterBreak = false; - } - return this; + /** + Whether the selection was explicitly set in this update. + */ + get selectionSet() { + return this.transactions.some(tr => tr.selection); } - get lineBreak() { return false; } + /** + @internal + */ + get empty() { return this.flags == 0 && this.transactions.length == 0; } } -if (typeof Symbol != "undefined") { - Text.prototype[Symbol.iterator] = function () { return this.iter(); }; - RawTextCursor.prototype[Symbol.iterator] = PartialTextCursor.prototype[Symbol.iterator] = - LineCursor.prototype[Symbol.iterator] = function () { return this; }; + +/** +Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). +*/ +exports.Direction = void 0; +(function (Direction) { + // (These are chosen to match the base levels, in bidi algorithm + // terms, of spans in that direction.) + /** + Left-to-right. + */ + Direction[Direction["LTR"] = 0] = "LTR"; + /** + Right-to-left. + */ + Direction[Direction["RTL"] = 1] = "RTL"; +})(exports.Direction || (exports.Direction = {})); +const LTR = exports.Direction.LTR, RTL = exports.Direction.RTL; +// Decode a string with each type encoded as log2(type) +function dec(str) { + let result = []; + for (let i = 0; i < str.length; i++) + result.push(1 << +str[i]); + return result; +} +// Character types for codepoints 0 to 0xf8 +const LowTypes = dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008"); +// Character types for codepoints 0x600 to 0x6f9 +const ArabicTypes = dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333"); +const Brackets = Object.create(null), BracketStack = []; +// There's a lot more in +// https://www.unicode.org/Public/UCD/latest/ucd/BidiBrackets.txt, +// which are left out to keep code size down. +for (let p of ["()", "[]", "{}"]) { + let l = p.charCodeAt(0), r = p.charCodeAt(1); + Brackets[l] = r; + Brackets[r] = -l; +} +function charType(ch) { + return ch <= 0xf7 ? LowTypes[ch] : + 0x590 <= ch && ch <= 0x5f4 ? 2 /* R */ : + 0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] : + 0x6ee <= ch && ch <= 0x8ac ? 4 /* AL */ : + 0x2000 <= ch && ch <= 0x200b ? 256 /* NI */ : + ch == 0x200c ? 256 /* NI */ : 1 /* L */; } +const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; /** -This type describes a line in the document. It is created -on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#text.Text.lineAt). +Represents a contiguous range of text that has a single direction +(as in left-to-right or right-to-left). */ -class Line { +class BidiSpan { /** @internal */ constructor( /** - The position of the start of the line. + The start of the span (relative to the start of the line). */ from, /** - The position at the end of the line (_before_ the line break, - or at the end of document for the last line). + The end of the span. */ to, /** - This line's line number (1-based). - */ - number, - /** - The line's content. + The ["bidi + level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm) + of the span (in this context, 0 means + left-to-right, 1 means right-to-left, 2 means left-to-right + number inside right-to-left text). */ - text) { + level) { this.from = from; this.to = to; - this.number = number; - this.text = text; + this.level = level; } /** - The length of the line (not including any line break after it). + The direction of this span. */ - get length() { return this.to - this.from; } + get dir() { return this.level % 2 ? RTL : LTR; } + /** + @internal + */ + side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; } + /** + @internal + */ + static find(order, index, level, assoc) { + let maybe = -1; + for (let i = 0; i < order.length; i++) { + let span = order[i]; + if (span.from <= index && span.to >= index) { + if (span.level == level) + return i; + // When multiple spans match, if assoc != 0, take the one that + // covers that side, otherwise take the one with the minimum + // level. + if (maybe < 0 || (assoc != 0 ? (assoc < 0 ? span.from < index : span.to > index) : order[maybe].level > span.level)) + maybe = i; + } + } + if (maybe < 0) + throw new RangeError("Index out of range"); + return maybe; + } } - -exports.Line = Line; -exports.Text = Text; -exports.codePointAt = codePointAt; -exports.codePointSize = codePointSize; -exports.countColumn = countColumn; -exports.findClusterBreak = findClusterBreak; -exports.findColumn = findColumn; -exports.fromCodePoint = fromCodePoint; - -},{}],53:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var view = require('@codemirror/view'); -var state = require('@codemirror/state'); - -const ios = typeof navigator != "undefined" && - !/Edge\/(\d+)/.exec(navigator.userAgent) && /Apple Computer/.test(navigator.vendor) && - (/Mobile\/\w+/.test(navigator.userAgent) || navigator.maxTouchPoints > 2); -const Outside = "-10000px"; -class TooltipViewManager { - constructor(view, facet, createTooltipView) { - this.facet = facet; - this.createTooltipView = createTooltipView; - this.input = view.state.facet(facet); - this.tooltips = this.input.filter(t => t); - this.tooltipViews = this.tooltips.map(createTooltipView); +// Reused array of character types +const types = []; +function computeOrder(line, direction) { + let len = line.length, outerType = direction == LTR ? 1 /* L */ : 2 /* R */, oppositeType = direction == LTR ? 2 /* R */ : 1 /* L */; + if (!line || outerType == 1 /* L */ && !BidiRE.test(line)) + return trivialOrder(len); + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + // (Left after this: L, R, EN, AN, ET, CS, NI) + for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) { + let type = charType(line.charCodeAt(i)); + if (type == 512 /* NSM */) + type = prev; + else if (type == 8 /* EN */ && prevStrong == 4 /* AL */) + type = 16 /* AN */; + types[i] = type == 4 /* AL */ ? 2 /* R */ : type; + if (type & 7 /* Strong */) + prevStrong = type; + prev = type; } - update(update) { - let input = update.state.facet(this.facet); - let tooltips = input.filter(x => x); - if (input === this.input) { - for (let t of this.tooltipViews) - if (t.update) - t.update(update); - return false; + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + // (Left after this: L, R, EN+AN, NI) + for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) { + let type = types[i]; + if (type == 128 /* CS */) { + if (i < len - 1 && prev == types[i + 1] && (prev & 24 /* Num */)) + type = types[i] = prev; + else + types[i] = 256 /* NI */; } - let tooltipViews = []; - for (let i = 0; i < tooltips.length; i++) { - let tip = tooltips[i], known = -1; - if (!tip) - continue; - for (let i = 0; i < this.tooltips.length; i++) { - let other = this.tooltips[i]; - if (other && other.create == tip.create) - known = i; + else if (type == 64 /* ET */) { + let end = i + 1; + while (end < len && types[end] == 64 /* ET */) + end++; + let replace = (i && prev == 8 /* EN */) || (end < len && types[end] == 8 /* EN */) ? (prevStrong == 1 /* L */ ? 1 /* L */ : 8 /* EN */) : 256 /* NI */; + for (let j = i; j < end; j++) + types[j] = replace; + i = end - 1; + } + else if (type == 8 /* EN */ && prevStrong == 1 /* L */) { + types[i] = 1 /* L */; + } + prev = type; + if (type & 7 /* Strong */) + prevStrong = type; + } + // N0. Process bracket pairs in an isolating run sequence + // sequentially in the logical order of the text positions of the + // opening paired brackets using the logic given below. Within this + // scope, bidirectional types EN and AN are treated as R. + for (let i = 0, sI = 0, context = 0, ch, br, type; i < len; i++) { + // Keeps [startIndex, type, strongSeen] triples for each open + // bracket on BracketStack. + if (br = Brackets[ch = line.charCodeAt(i)]) { + if (br < 0) { // Closing bracket + for (let sJ = sI - 3; sJ >= 0; sJ -= 3) { + if (BracketStack[sJ + 1] == -br) { + let flags = BracketStack[sJ + 2]; + let type = (flags & 2 /* EmbedInside */) ? outerType : + !(flags & 4 /* OppositeInside */) ? 0 : + (flags & 1 /* OppositeBefore */) ? oppositeType : outerType; + if (type) + types[i] = types[BracketStack[sJ]] = type; + sI = sJ; + break; + } + } } - if (known < 0) { - tooltipViews[i] = this.createTooltipView(tip); + else if (BracketStack.length == 189 /* MaxDepth */) { + break; } else { - let tooltipView = tooltipViews[i] = this.tooltipViews[known]; - if (tooltipView.update) - tooltipView.update(update); + BracketStack[sI++] = i; + BracketStack[sI++] = ch; + BracketStack[sI++] = context; } } - for (let t of this.tooltipViews) - if (tooltipViews.indexOf(t) < 0) - t.dom.remove(); - this.input = input; - this.tooltips = tooltips; - this.tooltipViews = tooltipViews; - return true; - } -} -/** -Return an extension that configures tooltip behavior. -*/ -function tooltips(config = {}) { - return tooltipConfig.of(config); -} -function windowSpace() { - return { top: 0, left: 0, bottom: innerHeight, right: innerWidth }; -} -const tooltipConfig = state.Facet.define({ - combine: values => { - var _a, _b, _c; - return ({ - position: ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed", - parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null, - tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace, - }); - } -}); -const tooltipPlugin = view.ViewPlugin.fromClass(class { - constructor(view) { - var _a; - this.view = view; - this.inView = true; - this.lastTransaction = 0; - this.measureTimeout = -1; - let config = view.state.facet(tooltipConfig); - this.position = config.position; - this.parent = config.parent; - this.classes = view.themeClasses; - this.createContainer(); - this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this }; - this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t)); - this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => { - if (Date.now() > this.lastTransaction - 50 && - entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1) - this.measureSoon(); - }, { threshold: [1] }) : null; - this.observeIntersection(); - (_a = view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this)); - this.maybeMeasure(); - } - createContainer() { - if (this.parent) { - this.container = document.createElement("div"); - this.container.style.position = "relative"; - this.container.className = this.view.themeClasses; - this.parent.appendChild(this.container); - } - else { - this.container = this.view.dom; + else if ((type = types[i]) == 2 /* R */ || type == 1 /* L */) { + let embed = type == outerType; + context = embed ? 0 : 1 /* OppositeBefore */; + for (let sJ = sI - 3; sJ >= 0; sJ -= 3) { + let cur = BracketStack[sJ + 2]; + if (cur & 2 /* EmbedInside */) + break; + if (embed) { + BracketStack[sJ + 2] |= 2 /* EmbedInside */; + } + else { + if (cur & 4 /* OppositeInside */) + break; + BracketStack[sJ + 2] |= 4 /* OppositeInside */; + } + } } } - observeIntersection() { - if (this.intersectionObserver) { - this.intersectionObserver.disconnect(); - for (let tooltip of this.manager.tooltipViews) - this.intersectionObserver.observe(tooltip.dom); + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + // (Left after this: L, R, EN+AN) + for (let i = 0; i < len; i++) { + if (types[i] == 256 /* NI */) { + let end = i + 1; + while (end < len && types[end] == 256 /* NI */) + end++; + let beforeL = (i ? types[i - 1] : outerType) == 1 /* L */; + let afterL = (end < len ? types[end] : outerType) == 1 /* L */; + let replace = beforeL == afterL ? (beforeL ? 1 /* L */ : 2 /* R */) : outerType; + for (let j = i; j < end; j++) + types[j] = replace; + i = end - 1; } } - measureSoon() { - if (this.measureTimeout < 0) - this.measureTimeout = setTimeout(() => { - this.measureTimeout = -1; - this.maybeMeasure(); - }, 50); - } - update(update) { - if (update.transactions.length) - this.lastTransaction = Date.now(); - let updated = this.manager.update(update); - if (updated) - this.observeIntersection(); - let shouldMeasure = updated || update.geometryChanged; - let newConfig = update.state.facet(tooltipConfig); - if (newConfig.position != this.position) { - this.position = newConfig.position; - for (let t of this.manager.tooltipViews) - t.dom.style.position = this.position; - shouldMeasure = true; - } - if (newConfig.parent != this.parent) { - if (this.parent) - this.container.remove(); - this.parent = newConfig.parent; - this.createContainer(); - for (let t of this.manager.tooltipViews) - this.container.appendChild(t.dom); - shouldMeasure = true; + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + let order = []; + if (outerType == 1 /* L */) { + for (let i = 0; i < len;) { + let start = i, rtl = types[i++] != 1 /* L */; + while (i < len && rtl == (types[i] != 1 /* L */)) + i++; + if (rtl) { + for (let j = i; j > start;) { + let end = j, l = types[--j] != 2 /* R */; + while (j > start && l == (types[j - 1] != 2 /* R */)) + j--; + order.push(new BidiSpan(j, end, l ? 2 : 1)); + } + } + else { + order.push(new BidiSpan(start, i, 0)); + } } - else if (this.parent && this.view.themeClasses != this.classes) { - this.classes = this.container.className = this.view.themeClasses; + } + else { + for (let i = 0; i < len;) { + let start = i, rtl = types[i++] == 2 /* R */; + while (i < len && rtl == (types[i] == 2 /* R */)) + i++; + order.push(new BidiSpan(start, i, rtl ? 1 : 2)); } - if (shouldMeasure) - this.maybeMeasure(); } - createTooltip(tooltip) { - let tooltipView = tooltip.create(this.view); - tooltipView.dom.classList.add("cm-tooltip"); - if (tooltip.arrow && !tooltipView.dom.querySelector("cm-tooltip > cm-tooltip-arrow")) { - let arrow = document.createElement("div"); - arrow.className = "cm-tooltip-arrow"; - tooltipView.dom.appendChild(arrow); + return order; +} +function trivialOrder(length) { + return [new BidiSpan(0, length, 0)]; +} +let movedOver = ""; +function moveVisually(line, order, dir, start, forward) { + var _a; + let startIndex = start.head - line.from, spanI = -1; + if (startIndex == 0) { + if (!forward || !line.length) + return null; + if (order[0].level != dir) { + startIndex = order[0].side(false, dir); + spanI = 0; } - tooltipView.dom.style.position = this.position; - tooltipView.dom.style.top = Outside; - this.container.appendChild(tooltipView.dom); - if (tooltipView.mount) - tooltipView.mount(this.view); - return tooltipView; } - destroy() { - var _a, _b; - (_a = this.view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener("resize", this.measureSoon); - for (let { dom } of this.manager.tooltipViews) - dom.remove(); - (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect(); - clearTimeout(this.measureTimeout); + else if (startIndex == line.length) { + if (forward) + return null; + let last = order[order.length - 1]; + if (last.level != dir) { + startIndex = last.side(true, dir); + spanI = order.length - 1; + } } - readMeasure() { - let editor = this.view.dom.getBoundingClientRect(); - return { - editor, - parent: this.parent ? this.container.getBoundingClientRect() : editor, - pos: this.manager.tooltips.map(t => this.view.coordsAtPos(t.pos)), - size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()), - space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view), - }; + if (spanI < 0) + spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc); + let span = order[spanI]; + // End of span. (But not end of line--that was checked for above.) + if (startIndex == span.side(forward, dir)) { + span = order[spanI += forward ? 1 : -1]; + startIndex = span.side(!forward, dir); } - writeMeasure(measured) { - let { editor, space } = measured; - let others = []; - for (let i = 0; i < this.manager.tooltips.length; i++) { - let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView; - let pos = measured.pos[i], size = measured.size[i]; - // Hide tooltips that are outside of the editor. - if (!pos || pos.bottom <= Math.max(editor.top, space.top) || - pos.top >= Math.min(editor.bottom, space.bottom) || - pos.right <= Math.max(editor.left, space.left) || - pos.left >= Math.min(editor.right, space.right)) { - dom.style.top = Outside; - continue; - } - let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null; - let arrowHeight = arrow ? 7 /* Size */ : 0; - let width = size.right - size.left, height = size.bottom - size.top; - let offset = tView.offset || noOffset, ltr = this.view.textDirection == view.Direction.LTR; - let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width) - : ltr ? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0) + offset.x, space.right - width) - : Math.max(space.left, pos.left - width + (arrow ? 14 /* Offset */ : 0) - offset.x); - let above = !!tooltip.above; - if (!tooltip.strictSide && (above - ? pos.top - (size.bottom - size.top) - offset.y < space.top - : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) && - above == (space.bottom - pos.bottom > pos.top - space.top)) - above = !above; - let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y; - let right = left + width; - if (tView.overlap !== true) - for (let r of others) - if (r.left < right && r.right > left && r.top < top + height && r.bottom > top) - top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2; - if (this.position == "absolute") { - dom.style.top = (top - measured.parent.top) + "px"; - dom.style.left = (left - measured.parent.left) + "px"; - } - else { - dom.style.top = top + "px"; - dom.style.left = left + "px"; - } - if (arrow) - arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Offset */ - 7 /* Size */)}px`; - if (tView.overlap !== true) - others.push({ left, top, right, bottom: top + height }); - dom.classList.toggle("cm-tooltip-above", above); - dom.classList.toggle("cm-tooltip-below", !above); - if (tView.positioned) - tView.positioned(); + let indexForward = forward == (span.dir == dir); + let nextIndex = text.findClusterBreak(line.text, startIndex, indexForward); + movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex)); + if (nextIndex != span.side(forward, dir)) + return state.EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level); + let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)]; + if (!nextSpan && span.level != dir) + return state.EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1, dir); + if (nextSpan && nextSpan.level < span.level) + return state.EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, forward ? 1 : -1, nextSpan.level); + return state.EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level); +} + +class DOMReader { + constructor(points, view) { + this.points = points; + this.view = view; + this.text = ""; + this.lineBreak = view.state.lineBreak; + } + readRange(start, end) { + if (!start) + return this; + let parent = start.parentNode; + for (let cur = start;;) { + this.findPointBefore(parent, cur); + this.readNode(cur); + let next = cur.nextSibling; + if (next == end) + break; + let view = ContentView.get(cur), nextView = ContentView.get(next); + if (view && nextView ? view.breakAfter : + (view ? view.breakAfter : isBlockElement(cur)) || + (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore))) + this.text += this.lineBreak; + cur = next; } + this.findPointBefore(parent, end); + return this; } - maybeMeasure() { - if (this.manager.tooltips.length) { - if (this.view.inView) - this.view.requestMeasure(this.measureReq); - if (this.inView != this.view.inView) { - this.inView = this.view.inView; - if (!this.inView) - for (let tv of this.manager.tooltipViews) - tv.dom.style.top = Outside; - } + readNode(node) { + if (node.cmIgnore) + return; + let view = ContentView.get(node); + let fromView = view && view.overrideDOMText; + let text; + if (fromView != null) + text = fromView.sliceString(0, undefined, this.lineBreak); + else if (node.nodeType == 3) + text = node.nodeValue; + else if (node.nodeName == "BR") + text = node.nextSibling ? this.lineBreak : ""; + else if (node.nodeType == 1) + this.readRange(node.firstChild, null); + if (text != null) { + this.findPointIn(node, text.length); + this.text += text; + // Chrome inserts two newlines when pressing shift-enter at the + // end of a line. This drops one of those. + if (browser.chrome && this.view.inputState.lastKeyCode == 13 && !node.nextSibling && /\n\n$/.test(this.text)) + this.text = this.text.slice(0, -1); } } -}, { - eventHandlers: { - scroll() { this.maybeMeasure(); } + findPointBefore(node, next) { + for (let point of this.points) + if (point.node == node && node.childNodes[point.offset] == next) + point.pos = this.text.length; } -}); -const baseTheme = view.EditorView.baseTheme({ - ".cm-tooltip": { - zIndex: 100 - }, - "&light .cm-tooltip": { - border: "1px solid #bbb", - backgroundColor: "#f5f5f5" - }, - "&light .cm-tooltip-section:not(:first-child)": { - borderTop: "1px solid #bbb", - }, - "&dark .cm-tooltip": { - backgroundColor: "#333338", - color: "white" - }, - ".cm-tooltip-arrow": { - height: `${7 /* Size */}px`, - width: `${7 /* Size */ * 2}px`, - position: "absolute", - zIndex: -1, - overflow: "hidden", - "&:before, &:after": { - content: "''", - position: "absolute", - width: 0, - height: 0, - borderLeft: `${7 /* Size */}px solid transparent`, - borderRight: `${7 /* Size */}px solid transparent`, - }, - ".cm-tooltip-above &": { - bottom: `-${7 /* Size */}px`, - "&:before": { - borderTop: `${7 /* Size */}px solid #bbb`, - }, - "&:after": { - borderTop: `${7 /* Size */}px solid #f5f5f5`, - bottom: "1px" - } - }, - ".cm-tooltip-below &": { - top: `-${7 /* Size */}px`, - "&:before": { - borderBottom: `${7 /* Size */}px solid #bbb`, - }, - "&:after": { - borderBottom: `${7 /* Size */}px solid #f5f5f5`, - top: "1px" - } - }, - }, - "&dark .cm-tooltip .cm-tooltip-arrow": { - "&:before": { - borderTopColor: "#333338", - borderBottomColor: "#333338" - }, - "&:after": { - borderTopColor: "transparent", - borderBottomColor: "transparent" - } + findPointIn(node, maxLen) { + for (let point of this.points) + if (point.node == node) + point.pos = this.text.length + Math.min(point.offset, maxLen); } -}); -const noOffset = { x: 0, y: 0 }; -/** -Behavior by which an extension can provide a tooltip to be shown. -*/ -const showTooltip = state.Facet.define({ - enables: [tooltipPlugin, baseTheme] -}); -const showHoverTooltip = state.Facet.define(); -class HoverTooltipHost { +} +function isBlockElement(node) { + return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName); +} +class DOMPoint { + constructor(node, offset) { + this.node = node; + this.offset = offset; + this.pos = -1; + } +} + +class DocView extends ContentView { constructor(view) { + super(); this.view = view; - this.mounted = false; - this.dom = document.createElement("div"); - this.dom.classList.add("cm-tooltip-hover"); - this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t)); + this.compositionDeco = Decoration.none; + this.decorations = []; + this.pluginDecorationLength = 0; + // Track a minimum width for the editor. When measuring sizes in + // measureVisibleLineHeights, this is updated to point at the width + // of a given element and its extent in the document. When a change + // happens in that range, these are reset. That way, once we've seen + // a line/element of a given length, we keep the editor wide enough + // to fit at least that element, until it is changed, at which point + // we forget it again. + this.minWidth = 0; + this.minWidthFrom = 0; + this.minWidthTo = 0; + // Track whether the DOM selection was set in a lossy way, so that + // we don't mess it up when reading it back it + this.impreciseAnchor = null; + this.impreciseHead = null; + this.forceSelection = false; + // Used by the resize observer to ignore resizes that we caused + // ourselves + this.lastUpdate = Date.now(); + this.setDOM(view.contentDOM); + this.children = [new LineView]; + this.children[0].setParent(this); + this.updateDeco(); + this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0); } - // Needs to be static so that host tooltip instances always match - static create(view) { - return new HoverTooltipHost(view); + get root() { return this.view.root; } + get editorView() { return this.view; } + get length() { return this.view.state.doc.length; } + // Update the document view to a given state. scrollIntoView can be + // used as a hint to compute a new viewport that includes that + // position, if we know the editor is going to scroll that position + // into view. + update(update) { + let changedRanges = update.changedRanges; + if (this.minWidth > 0 && changedRanges.length) { + if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) { + this.minWidth = this.minWidthFrom = this.minWidthTo = 0; + } + else { + this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1); + this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1); + } + } + if (this.view.inputState.composing < 0) + this.compositionDeco = Decoration.none; + else if (update.transactions.length || this.dirty) + this.compositionDeco = computeCompositionDeco(this.view, update.changes); + // When the DOM nodes around the selection are moved to another + // parent, Chrome sometimes reports a different selection through + // getSelection than the one that it actually shows to the user. + // This forces a selection update when lines are joined to work + // around that. Issue #54 + if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update && + update.state.doc.lines != update.startState.doc.lines) + this.forceSelection = true; + let prevDeco = this.decorations, deco = this.updateDeco(); + let decoDiff = findChangedDeco(prevDeco, deco, update.changes); + changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff); + if (this.dirty == 0 /* Not */ && changedRanges.length == 0) { + return false; + } + else { + this.updateInner(changedRanges, update.startState.doc.length); + if (update.transactions.length) + this.lastUpdate = Date.now(); + return true; + } } - createHostedView(tooltip) { - let hostedView = tooltip.create(this.view); - hostedView.dom.classList.add("cm-tooltip-section"); - this.dom.appendChild(hostedView.dom); - if (this.mounted && hostedView.mount) - hostedView.mount(this.view); - return hostedView; + // Used by update and the constructor do perform the actual DOM + // update + updateInner(changes, oldLength) { + this.view.viewState.mustMeasureContent = true; + this.updateChildren(changes, oldLength); + let { observer } = this.view; + observer.ignore(() => { + // Lock the height during redrawing, since Chrome sometimes + // messes with the scroll position during DOM mutation (though + // no relayout is triggered and I cannot imagine how it can + // recompute the scroll position without a layout) + this.dom.style.height = this.view.viewState.contentHeight + "px"; + this.dom.style.minWidth = this.minWidth ? this.minWidth + "px" : ""; + // Chrome will sometimes, when DOM mutations occur directly + // around the selection, get confused and report a different + // selection from the one it displays (issue #218). This tries + // to detect that situation. + let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined; + this.sync(track); + this.dirty = 0 /* Not */; + if (track && (track.written || observer.selectionRange.focusNode != track.node)) + this.forceSelection = true; + this.dom.style.height = ""; + }); + let gaps = []; + if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length) + for (let child of this.children) + if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget) + gaps.push(child.dom); + observer.updateGaps(gaps); } - mount(view) { - for (let hostedView of this.manager.tooltipViews) { - if (hostedView.mount) - hostedView.mount(view); + updateChildren(changes, oldLength) { + let cursor = this.childCursor(oldLength); + for (let i = changes.length - 1;; i--) { + let next = i >= 0 ? changes[i] : null; + if (!next) + break; + let { fromA, toA, fromB, toB } = next; + let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.pluginDecorationLength); + let { i: toI, off: toOff } = cursor.findPos(toA, 1); + let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1); + replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd); } - this.mounted = true; } - positioned() { - for (let hostedView of this.manager.tooltipViews) { - if (hostedView.positioned) - hostedView.positioned(); + // Sync the DOM selection to this.state.selection + updateSelection(mustRead = false, fromPointer = false) { + if (mustRead) + this.view.observer.readSelectionRange(); + if (!(fromPointer || this.mayControlSelection()) || + browser.ios && this.view.inputState.rapidCompositionStart) + return; + let force = this.forceSelection; + this.forceSelection = false; + let main = this.view.state.selection.main; + // FIXME need to handle the case where the selection falls inside a block range + let anchor = this.domAtPos(main.anchor); + let head = main.empty ? anchor : this.domAtPos(main.head); + // Always reset on Firefox when next to an uneditable node to + // avoid invisible cursor bugs (#111) + if (browser.gecko && main.empty && betweenUneditable(anchor)) { + let dummy = document.createTextNode(""); + this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null)); + anchor = head = new DOMPos(dummy, 0); + force = true; + } + let domSel = this.view.observer.selectionRange; + // If the selection is already here, or in an equivalent position, don't touch it + if (force || !domSel.focusNode || + !isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) || + !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) { + this.view.observer.ignore(() => { + // Chrome Android will hide the virtual keyboard when tapping + // inside an uneditable node, and not bring it back when we + // move the cursor to its proper position. This tries to + // restore the keyboard by cycling focus. + if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && + inUneditable(domSel.focusNode, this.dom)) { + this.dom.blur(); + this.dom.focus({ preventScroll: true }); + } + let rawSel = getSelection(this.root); + if (main.empty) { + // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076 + if (browser.gecko) { + let nextTo = nextToUneditable(anchor.node, anchor.offset); + if (nextTo && nextTo != (1 /* Before */ | 2 /* After */)) { + let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* Before */ ? 1 : -1); + if (text) + anchor = new DOMPos(text, nextTo == 1 /* Before */ ? 0 : text.nodeValue.length); + } + } + rawSel.collapse(anchor.node, anchor.offset); + if (main.bidiLevel != null && domSel.cursorBidiLevel != null) + domSel.cursorBidiLevel = main.bidiLevel; + } + else if (rawSel.extend) { + // Selection.extend can be used to create an 'inverted' selection + // (one where the focus is before the anchor), but not all + // browsers support it yet. + rawSel.collapse(anchor.node, anchor.offset); + rawSel.extend(head.node, head.offset); + } + else { + // Primitive (IE) way + let range = document.createRange(); + if (main.anchor > main.head) + [anchor, head] = [head, anchor]; + range.setEnd(head.node, head.offset); + range.setStart(anchor.node, anchor.offset); + rawSel.removeAllRanges(); + rawSel.addRange(range); + } + }); + this.view.observer.setSelectionRange(anchor, head); } + this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset); + this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset); } - update(update) { - this.manager.update(update); + enforceCursorAssoc() { + if (this.compositionDeco.size) + return; + let cursor = this.view.state.selection.main; + let sel = getSelection(this.root); + if (!cursor.empty || !cursor.assoc || !sel.modify) + return; + let line = LineView.find(this, cursor.head); + if (!line) + return; + let lineStart = line.posAtStart; + if (cursor.head == lineStart || cursor.head == lineStart + line.length) + return; + let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1); + if (!before || !after || before.bottom > after.top) + return; + let dom = this.domAtPos(cursor.head + cursor.assoc); + sel.collapse(dom.node, dom.offset); + sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary"); } -} -const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => { - let tooltips = state.facet(showHoverTooltip).filter(t => t); - if (tooltips.length === 0) - return null; - return { - pos: Math.min(...tooltips.map(t => t.pos)), - end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)), - create: HoverTooltipHost.create, - above: tooltips[0].above, - arrow: tooltips.some(t => t.arrow), - }; -}); -class HoverPlugin { - constructor(view, source, field, setHover, hoverTime) { - this.view = view; - this.source = source; - this.field = field; - this.setHover = setHover; - this.hoverTime = hoverTime; - this.hoverTimeout = -1; - this.restartTimeout = -1; - this.pending = null; - this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 }; - this.checkHover = this.checkHover.bind(this); - view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this)); - view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this)); + mayControlSelection() { + return this.view.state.facet(editable) ? this.root.activeElement == this.dom + : hasSelection(this.dom, this.view.observer.selectionRange); } - update() { - if (this.pending) { - this.pending = null; - clearTimeout(this.restartTimeout); - this.restartTimeout = setTimeout(() => this.startHover(), 20); + nearest(dom) { + for (let cur = dom; cur;) { + let domView = ContentView.get(cur); + if (domView && domView.rootView == this) + return domView; + cur = cur.parentNode; } + return null; } - get active() { - return this.view.state.field(this.field); + posFromDOM(node, offset) { + let view = this.nearest(node); + if (!view) + throw new RangeError("Trying to find position for a DOM position outside of the document"); + return view.localPosFromDOM(node, offset) + view.posAtStart; } - checkHover() { - this.hoverTimeout = -1; - if (this.active) - return; - let hovered = Date.now() - this.lastMove.time; - if (hovered < this.hoverTime) - this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered); - else - this.startHover(); + domAtPos(pos) { + let { i, off } = this.childCursor().findPos(pos, -1); + for (; i < this.children.length - 1;) { + let child = this.children[i]; + if (off < child.length || child instanceof LineView) + break; + i++; + off = 0; + } + return this.children[i].domAtPos(off); } - startHover() { - var _a; - clearTimeout(this.restartTimeout); - let { lastMove } = this; - let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null; - if (pos == null) - return; - let posCoords = this.view.coordsAtPos(pos); - if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom || - lastMove.x < posCoords.left - this.view.defaultCharacterWidth || - lastMove.x > posCoords.right + this.view.defaultCharacterWidth) - return; - let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos); - let rtl = bidi && bidi.dir == view.Direction.RTL ? -1 : 1; - let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl)); - if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) { - let pending = this.pending = { pos }; - open.then(result => { - if (this.pending == pending) { - this.pending = null; - if (result) - this.view.dispatch({ effects: this.setHover.of(result) }); - } - }, e => view.logException(this.view.state, e, "hover tooltip")); + coordsAt(pos, side) { + for (let off = this.length, i = this.children.length - 1;; i--) { + let child = this.children[i], start = off - child.breakAfter - child.length; + if (pos > start || + (pos == start && child.type != exports.BlockType.WidgetBefore && child.type != exports.BlockType.WidgetAfter && + (!i || side == 2 || this.children[i - 1].breakAfter || + (this.children[i - 1].type == exports.BlockType.WidgetBefore && side > -2)))) + return child.coordsAt(pos - start, side); + off = start; } - else if (open) { - this.view.dispatch({ effects: this.setHover.of(open) }); + } + measureVisibleLineHeights() { + let result = [], { from, to } = this.view.viewState.viewport; + let contentWidth = this.view.contentDOM.clientWidth; + let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1; + let widest = -1; + for (let pos = 0, i = 0; i < this.children.length; i++) { + let child = this.children[i], end = pos + child.length; + if (end > to) + break; + if (pos >= from) { + let childRect = child.dom.getBoundingClientRect(); + result.push(childRect.height); + if (isWider) { + let last = child.dom.lastChild; + let rects = last ? clientRectsFor(last) : []; + if (rects.length) { + let rect = rects[rects.length - 1]; + let width = this.view.textDirection == exports.Direction.LTR ? rect.right - childRect.left + : childRect.right - rect.left; + if (width > widest) { + widest = width; + this.minWidth = contentWidth; + this.minWidthFrom = pos; + this.minWidthTo = end; + } + } + } + } + pos = end + child.breakAfter; } + return result; } - mousemove(event) { - var _a; - this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() }; - if (this.hoverTimeout < 0) - this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime); - let tooltip = this.active; - if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) { - let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos; - if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos - : !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) { - this.view.dispatch({ effects: this.setHover.of(null) }); - this.pending = null; + measureTextSize() { + for (let child of this.children) { + if (child instanceof LineView) { + let measure = child.measureTextSize(); + if (measure) + return measure; } } + // If no workable line exists, force a layout of a measurable element + let dummy = document.createElement("div"), lineHeight, charWidth; + dummy.className = "cm-line"; + dummy.textContent = "abc def ghi jkl mno pqr stu"; + this.view.observer.ignore(() => { + this.dom.appendChild(dummy); + let rect = clientRectsFor(dummy.firstChild)[0]; + lineHeight = dummy.getBoundingClientRect().height; + charWidth = rect ? rect.width / 27 : 7; + dummy.remove(); + }); + return { lineHeight, charWidth }; } - mouseleave() { - clearTimeout(this.hoverTimeout); - this.hoverTimeout = -1; - if (this.active) - this.view.dispatch({ effects: this.setHover.of(null) }); + childCursor(pos = this.length) { + // Move back to start of last element when possible, so that + // `ChildCursor.findPos` doesn't have to deal with the edge case + // of being after the last element. + let i = this.children.length; + if (i) + pos -= this.children[--i].length; + return new ChildCursor(this.children, pos, i); } - destroy() { - clearTimeout(this.hoverTimeout); - this.view.dom.removeEventListener("mouseleave", this.mouseleave); - this.view.dom.removeEventListener("mousemove", this.mousemove); + computeBlockGapDeco() { + let deco = [], vs = this.view.viewState; + for (let pos = 0, i = 0;; i++) { + let next = i == vs.viewports.length ? null : vs.viewports[i]; + let end = next ? next.from - 1 : this.length; + if (end > pos) { + let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top; + deco.push(Decoration.replace({ widget: new BlockGapWidget(height), block: true, inclusive: true }).range(pos, end)); + } + if (!next) + break; + pos = next.to + 1; + } + return Decoration.set(deco); } -} -function isInTooltip(elt) { - for (let cur = elt; cur; cur = cur.parentNode) - if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip")) - return true; - return false; -} -function isOverRange(view, from, to, x, y, margin) { - let range = document.createRange(); - let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to); - range.setEnd(toDOM.node, toDOM.offset); - range.setStart(fromDOM.node, fromDOM.offset); - let rects = range.getClientRects(); - range.detach(); - for (let i = 0; i < rects.length; i++) { - let rect = rects[i]; - let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right); - if (dist <= margin) - return true; + updateDeco() { + let pluginDecorations = this.view.pluginField(PluginField.decorations); + this.pluginDecorationLength = pluginDecorations.length; + return this.decorations = [ + ...pluginDecorations, + ...this.view.state.facet(decorations), + this.compositionDeco, + this.computeBlockGapDeco(), + this.view.viewState.lineGapDeco + ]; } - return false; -} -/** -Enable a hover tooltip, which shows up when the pointer hovers -over ranges of text. The callback is called when the mouse hovers -over the document text. It should, if there is a tooltip -associated with position `pos` return the tooltip description -(either directly or in a promise). The `side` argument indicates -on which side of the position the pointer is—it will be -1 if the -pointer is before the position, 1 if after the position. - -Note that all hover tooltips are hosted within a single tooltip -container element. This allows multiple tooltips over the same -range to be "merged" together without overlapping. -*/ -function hoverTooltip(source, options = {}) { - let setHover = state.StateEffect.define(); - let hoverState = state.StateField.define({ - create() { return null; }, - update(value, tr) { - if (value && (options.hideOnChange && (tr.docChanged || tr.selection))) - return null; - for (let effect of tr.effects) { - if (effect.is(setHover)) - return effect.value; - if (effect.is(closeHoverTooltipEffect)) - return null; - } - if (value && tr.docChanged) { - let newPos = tr.changes.mapPos(value.pos, -1, state.MapMode.TrackDel); - if (newPos == null) - return null; - let copy = Object.assign(Object.create(null), value); - copy.pos = newPos; - if (value.end != null) - copy.end = tr.changes.mapPos(value.end); - return copy; + scrollIntoView(target) { + let { range } = target; + let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other; + if (!rect) + return; + if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1))) + rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top), + right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) }; + let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0; + for (let margins of this.view.pluginField(PluginField.scrollMargins)) + if (margins) { + let { left, right, top, bottom } = margins; + if (left != null) + mLeft = Math.max(mLeft, left); + if (right != null) + mRight = Math.max(mRight, right); + if (top != null) + mTop = Math.max(mTop, top); + if (bottom != null) + mBottom = Math.max(mBottom, bottom); } - return value; - }, - provide: f => showHoverTooltip.from(f) - }); - let hoverTime = options.hoverTime || 600 /* Time */; - return [ - hoverState, - view.ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, hoverTime)), - showHoverTooltipHost - ]; -} -/** -Get the active tooltip view for a given tooltip, if available. -*/ -function getTooltip(view, tooltip) { - let plugin = view.plugin(tooltipPlugin); - if (!plugin) - return null; - let found = plugin.manager.tooltips.indexOf(tooltip); - return found < 0 ? null : plugin.manager.tooltipViews[found]; + let targetRect = { + left: rect.left - mLeft, top: rect.top - mTop, + right: rect.right + mRight, bottom: rect.bottom + mBottom + }; + scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, target.xMargin, target.yMargin, this.view.textDirection == exports.Direction.LTR); + } } -/** -Returns true if any hover tooltips are currently active. -*/ -function hasHoverTooltips(state) { - return state.facet(showHoverTooltip).some(x => x); +function betweenUneditable(pos) { + return pos.node.nodeType == 1 && pos.node.firstChild && + (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") && + (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false"); } -const closeHoverTooltipEffect = state.StateEffect.define(); -/** -Transaction effect that closes all hover tooltips. -*/ -const closeHoverTooltips = closeHoverTooltipEffect.of(null); -/** -Tell the tooltip extension to recompute the position of the active -tooltips. This can be useful when something happens (such as a -re-positioning or CSS change affecting the editor) that could -invalidate the existing tooltip positions. -*/ -function repositionTooltips(view) { - var _a; - (_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure(); +class BlockGapWidget extends WidgetType { + constructor(height) { + super(); + this.height = height; + } + toDOM() { + let elt = document.createElement("div"); + this.updateDOM(elt); + return elt; + } + eq(other) { return other.height == this.height; } + updateDOM(elt) { + elt.style.height = this.height + "px"; + return true; + } + get estimatedHeight() { return this.height; } } - -exports.closeHoverTooltips = closeHoverTooltips; -exports.getTooltip = getTooltip; -exports.hasHoverTooltips = hasHoverTooltips; -exports.hoverTooltip = hoverTooltip; -exports.repositionTooltips = repositionTooltips; -exports.showTooltip = showTooltip; -exports.tooltips = tooltips; - -},{"@codemirror/state":51,"@codemirror/view":54}],54:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var state = require('@codemirror/state'); -var styleMod = require('style-mod'); -var rangeset = require('@codemirror/rangeset'); -var text = require('@codemirror/text'); -var w3cKeyname = require('w3c-keyname'); - -function getSelection(root) { - let target; - // Browsers differ on whether shadow roots have a getSelection - // method. If it exists, use that, otherwise, call it on the - // document. - if (root.nodeType == 11) { // Shadow root - target = root.getSelection ? root : root.ownerDocument; +function computeCompositionDeco(view, changes) { + let sel = view.observer.selectionRange; + let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0); + if (!textNode) + return Decoration.none; + let cView = view.docView.nearest(textNode); + if (!cView) + return Decoration.none; + let from, to, topNode = textNode; + if (cView instanceof LineView) { + while (topNode.parentNode != cView.dom) + topNode = topNode.parentNode; + let prev = topNode.previousSibling; + while (prev && !ContentView.get(prev)) + prev = prev.previousSibling; + from = to = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart; } else { - target = root; + for (;;) { + let { parent } = cView; + if (!parent) + return Decoration.none; + if (parent instanceof LineView) + break; + cView = parent; + } + from = cView.posAtStart; + to = from + cView.length; + topNode = cView.dom; } - return target.getSelection(); -} -function contains(dom, node) { - return node ? dom.contains(node.nodeType != 1 ? node.parentNode : node) : false; -} -function deepActiveElement() { - let elt = document.activeElement; - while (elt && elt.shadowRoot) - elt = elt.shadowRoot.activeElement; - return elt; -} -function hasSelection(dom, selection) { - if (!selection.anchorNode) - return false; - try { - // Firefox will raise 'permission denied' errors when accessing - // properties of `sel.anchorNode` when it's in a generated CSS - // element. - return contains(dom, selection.anchorNode); + let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1)); + let { state } = view, text = topNode.nodeType == 3 ? topNode.nodeValue : + new DOMReader([], view).readRange(topNode.firstChild, null).text; + if (newTo - newFrom < text.length) { + if (state.sliceDoc(newFrom, Math.min(state.doc.length, newFrom + text.length)) == text) + newTo = newFrom + text.length; + else if (state.sliceDoc(Math.max(0, newTo - text.length), newTo) == text) + newFrom = newTo - text.length; + else + return Decoration.none; } - catch (_) { - return false; + else if (state.sliceDoc(newFrom, newTo) != text) { + return Decoration.none; } + return Decoration.set(Decoration.replace({ widget: new CompositionWidget(topNode, textNode) }).range(newFrom, newTo)); } -function clientRectsFor(dom) { - if (dom.nodeType == 3) - return textRange(dom, 0, dom.nodeValue.length).getClientRects(); - else if (dom.nodeType == 1) - return dom.getClientRects(); - else - return []; -} -// Scans forward and backward through DOM positions equivalent to the -// given one to see if the two are in the same place (i.e. after a -// text node vs at the end of that text node) -function isEquivalentPosition(node, off, targetNode, targetOff) { - return targetNode ? (scanFor(node, off, targetNode, targetOff, -1) || - scanFor(node, off, targetNode, targetOff, 1)) : false; -} -function domIndex(node) { - for (var index = 0;; index++) { - node = node.previousSibling; - if (!node) - return index; +class CompositionWidget extends WidgetType { + constructor(top, text) { + super(); + this.top = top; + this.text = text; } + eq(other) { return this.top == other.top && this.text == other.text; } + toDOM() { return this.top; } + ignoreEvent() { return false; } + get customView() { return CompositionView; } } -function scanFor(node, off, targetNode, targetOff, dir) { +function nearbyTextNode(node, offset, side) { for (;;) { - if (node == targetNode && off == targetOff) - return true; - if (off == (dir < 0 ? 0 : maxOffset(node))) { - if (node.nodeName == "DIV") - return false; - let parent = node.parentNode; - if (!parent || parent.nodeType != 1) - return false; - off = domIndex(node) + (dir < 0 ? 0 : 1); - node = parent; + if (node.nodeType == 3) + return node; + if (node.nodeType == 1 && offset > 0 && side <= 0) { + node = node.childNodes[offset - 1]; + offset = maxOffset(node); } - else if (node.nodeType == 1) { - node = node.childNodes[off + (dir < 0 ? -1 : 0)]; - if (node.nodeType == 1 && node.contentEditable == "false") - return false; - off = dir < 0 ? maxOffset(node) : 0; + else if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) { + node = node.childNodes[offset]; + offset = 0; } else { - return false; + return null; + } + } +} +function nextToUneditable(node, offset) { + if (node.nodeType != 1) + return 0; + return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 /* Before */ : 0) | + (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 /* After */ : 0); +} +class DecorationComparator$1 { + constructor() { + this.changes = []; + } + compareRange(from, to) { addRange(from, to, this.changes); } + comparePoint(from, to) { addRange(from, to, this.changes); } +} +function findChangedDeco(a, b, diff) { + let comp = new DecorationComparator$1; + rangeset.RangeSet.compare(a, b, diff, comp); + return comp.changes; +} +function inUneditable(node, inside) { + for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) { + if (cur.nodeType == 1 && cur.contentEditable == 'false') { + return true; } } + return false; +} + +function groupAt(state$1, pos, bias = 1) { + let categorize = state$1.charCategorizer(pos); + let line = state$1.doc.lineAt(pos), linePos = pos - line.from; + if (line.length == 0) + return state.EditorSelection.cursor(pos); + if (linePos == 0) + bias = 1; + else if (linePos == line.length) + bias = -1; + let from = linePos, to = linePos; + if (bias < 0) + from = text.findClusterBreak(line.text, linePos, false); + else + to = text.findClusterBreak(line.text, linePos); + let cat = categorize(line.text.slice(from, to)); + while (from > 0) { + let prev = text.findClusterBreak(line.text, from, false); + if (categorize(line.text.slice(prev, from)) != cat) + break; + from = prev; + } + while (to < line.length) { + let next = text.findClusterBreak(line.text, to); + if (categorize(line.text.slice(to, next)) != cat) + break; + to = next; + } + return state.EditorSelection.range(from + line.from, to + line.from); +} +// Search the DOM for the {node, offset} position closest to the given +// coordinates. Very inefficient and crude, but can usually be avoided +// by calling caret(Position|Range)FromPoint instead. +function getdx(x, rect) { + return rect.left > x ? rect.left - x : Math.max(0, x - rect.right); } -function maxOffset(node) { - return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length; +function getdy(y, rect) { + return rect.top > y ? rect.top - y : Math.max(0, y - rect.bottom); } -const Rect0 = { left: 0, right: 0, top: 0, bottom: 0 }; -function flattenRect(rect, left) { - let x = left ? rect.left : rect.right; - return { left: x, right: x, top: rect.top, bottom: rect.bottom }; +function yOverlap(a, b) { + return a.top < b.bottom - 1 && a.bottom > b.top + 1; } -function windowRect(win) { - return { left: 0, right: win.innerWidth, - top: 0, bottom: win.innerHeight }; +function upTop(rect, top) { + return top < rect.top ? { top, left: rect.left, right: rect.right, bottom: rect.bottom } : rect; } -function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) { - let doc = dom.ownerDocument, win = doc.defaultView; - for (let cur = dom; cur;) { - if (cur.nodeType == 1) { // Element - let bounding, top = cur == doc.body; - if (top) { - bounding = windowRect(win); - } - else { - if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) { - cur = cur.parentNode; - continue; - } - let rect = cur.getBoundingClientRect(); - // Make sure scrollbar width isn't included in the rectangle - bounding = { left: rect.left, right: rect.left + cur.clientWidth, - top: rect.top, bottom: rect.top + cur.clientHeight }; - } - let moveX = 0, moveY = 0; - if (y == "nearest") { - if (rect.top < bounding.top) { - moveY = -(bounding.top - rect.top + yMargin); - if (side > 0 && rect.bottom > bounding.bottom + moveY) - moveY = rect.bottom - bounding.bottom + moveY + yMargin; - } - else if (rect.bottom > bounding.bottom) { - moveY = rect.bottom - bounding.bottom + yMargin; - if (side < 0 && (rect.top - moveY) < bounding.top) - moveY = -(bounding.top + moveY - rect.top + yMargin); - } - } - else { - let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top; - let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 : - y == "start" || y == "center" && side < 0 ? rect.top - yMargin : - rect.bottom - boundingHeight + yMargin; - moveY = targetTop - bounding.top; +function upBot(rect, bottom) { + return bottom > rect.bottom ? { top: rect.top, left: rect.left, right: rect.right, bottom } : rect; +} +function domPosAtCoords(parent, x, y) { + let closest, closestRect, closestX, closestY; + let above, below, aboveRect, belowRect; + for (let child = parent.firstChild; child; child = child.nextSibling) { + let rects = clientRectsFor(child); + for (let i = 0; i < rects.length; i++) { + let rect = rects[i]; + if (closestRect && yOverlap(closestRect, rect)) + rect = upTop(upBot(rect, closestRect.bottom), closestRect.top); + let dx = getdx(x, rect), dy = getdy(y, rect); + if (dx == 0 && dy == 0) + return child.nodeType == 3 ? domPosInText(child, x, y) : domPosAtCoords(child, x, y); + if (!closest || closestY > dy || closestY == dy && closestX > dx) { + closest = child; + closestRect = rect; + closestX = dx; + closestY = dy; } - if (x == "nearest") { - if (rect.left < bounding.left) { - moveX = -(bounding.left - rect.left + xMargin); - if (side > 0 && rect.right > bounding.right + moveX) - moveX = rect.right - bounding.right + moveX + xMargin; + if (dx == 0) { + if (y > rect.bottom && (!aboveRect || aboveRect.bottom < rect.bottom)) { + above = child; + aboveRect = rect; } - else if (rect.right > bounding.right) { - moveX = rect.right - bounding.right + xMargin; - if (side < 0 && rect.left < bounding.left + moveX) - moveX = -(bounding.left + moveX - rect.left + xMargin); + else if (y < rect.top && (!belowRect || belowRect.top > rect.top)) { + below = child; + belowRect = rect; } } - else { - let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 : - (x == "start") == ltr ? rect.left - xMargin : - rect.right - (bounding.right - bounding.left) + xMargin; - moveX = targetLeft - bounding.left; + else if (aboveRect && yOverlap(aboveRect, rect)) { + aboveRect = upBot(aboveRect, rect.bottom); } - if (moveX || moveY) { - if (top) { - win.scrollBy(moveX, moveY); - } - else { - if (moveY) { - let start = cur.scrollTop; - cur.scrollTop += moveY; - moveY = cur.scrollTop - start; - } - if (moveX) { - let start = cur.scrollLeft; - cur.scrollLeft += moveX; - moveX = cur.scrollLeft - start; - } - rect = { left: rect.left - moveX, top: rect.top - moveY, - right: rect.right - moveX, bottom: rect.bottom - moveY }; - } + else if (belowRect && yOverlap(belowRect, rect)) { + belowRect = upTop(belowRect, rect.top); } - if (top) - break; - cur = cur.assignedSlot || cur.parentNode; - x = y = "nearest"; } - else if (cur.nodeType == 11) { // A shadow root - cur = cur.host; - } - else { - break; - } - } -} -class DOMSelectionState { - constructor() { - this.anchorNode = null; - this.anchorOffset = 0; - this.focusNode = null; - this.focusOffset = 0; } - eq(domSel) { - return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset && - this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset; + if (aboveRect && aboveRect.bottom >= y) { + closest = above; + closestRect = aboveRect; } - setRange(range) { - this.set(range.anchorNode, range.anchorOffset, range.focusNode, range.focusOffset); + else if (belowRect && belowRect.top <= y) { + closest = below; + closestRect = belowRect; } - set(anchorNode, anchorOffset, focusNode, focusOffset) { - this.anchorNode = anchorNode; - this.anchorOffset = anchorOffset; - this.focusNode = focusNode; - this.focusOffset = focusOffset; + if (!closest) + return { node: parent, offset: 0 }; + let clipX = Math.max(closestRect.left, Math.min(closestRect.right, x)); + if (closest.nodeType == 3) + return domPosInText(closest, clipX, y); + if (!closestX && closest.contentEditable == "true") + return domPosAtCoords(closest, clipX, y); + let offset = Array.prototype.indexOf.call(parent.childNodes, closest) + + (x >= (closestRect.left + closestRect.right) / 2 ? 1 : 0); + return { node: parent, offset }; +} +function domPosInText(node, x, y) { + let len = node.nodeValue.length; + let closestOffset = -1, closestDY = 1e9, generalSide = 0; + for (let i = 0; i < len; i++) { + let rects = textRange(node, i, i + 1).getClientRects(); + for (let j = 0; j < rects.length; j++) { + let rect = rects[j]; + if (rect.top == rect.bottom) + continue; + if (!generalSide) + generalSide = x - rect.left; + let dy = (rect.top > y ? rect.top - y : y - rect.bottom) - 1; + if (rect.left - 1 <= x && rect.right + 1 >= x && dy < closestDY) { + let right = x >= (rect.left + rect.right) / 2, after = right; + if (browser.chrome || browser.gecko) { + // Check for RTL on browsers that support getting client + // rects for empty ranges. + let rectBefore = textRange(node, i).getBoundingClientRect(); + if (rectBefore.left == rect.right) + after = !right; + } + if (dy <= 0) + return { node, offset: i + (after ? 1 : 0) }; + closestOffset = i + (after ? 1 : 0); + closestDY = dy; + } + } } + return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 }; } -let preventScrollSupported = null; -// Feature-detects support for .focus({preventScroll: true}), and uses -// a fallback kludge when not supported. -function focusPreventScroll(dom) { - if (dom.setActive) - return dom.setActive(); // in IE - if (preventScrollSupported) - return dom.focus(preventScrollSupported); - let stack = []; - for (let cur = dom; cur; cur = cur.parentNode) { - stack.push(cur, cur.scrollTop, cur.scrollLeft); - if (cur == cur.ownerDocument) +function posAtCoords(view, { x, y }, precise, bias = -1) { + var _a; + let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop; + let block, { docHeight } = view.viewState; + let yOffset = y - docTop; + if (yOffset < 0) + return 0; + if (yOffset > docHeight) + return view.state.doc.length; + // Scan for a text block near the queried y position + for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) { + block = view.elementAtHeight(yOffset); + if (block.type == exports.BlockType.Text) break; + for (;;) { + // Move the y position out of this block + yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine; + if (yOffset >= 0 && yOffset <= docHeight) + break; + // If the document consists entirely of replaced widgets, we + // won't find a text block, so return 0 + if (bounced) + return precise ? null : 0; + bounced = true; + bias = -bias; + } } - dom.focus(preventScrollSupported == null ? { - get preventScroll() { - preventScrollSupported = { preventScroll: true }; - return true; + y = docTop + yOffset; + let lineStart = block.from; + // If this is outside of the rendered viewport, we can't determine a position + if (lineStart < view.viewport.from) + return view.viewport.from == 0 ? 0 : precise ? null : posAtCoordsImprecise(view, content, block, x, y); + if (lineStart > view.viewport.to) + return view.viewport.to == view.state.doc.length ? view.state.doc.length : + precise ? null : posAtCoordsImprecise(view, content, block, x, y); + // Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not + let doc = view.dom.ownerDocument; + let root = view.root.elementFromPoint ? view.root : doc; + let element = root.elementFromPoint(x, y); + if (element && !view.contentDOM.contains(element)) + element = null; + // If the element is unexpected, clip x at the sides of the content area and try again + if (!element) { + x = Math.max(content.left + 1, Math.min(content.right - 1, x)); + element = root.elementFromPoint(x, y); + if (element && !view.contentDOM.contains(element)) + element = null; + } + // There's visible editor content under the point, so we can try + // using caret(Position|Range)FromPoint as a shortcut + let node, offset = -1; + if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) { + if (doc.caretPositionFromPoint) { + let pos = doc.caretPositionFromPoint(x, y); + if (pos) + ({ offsetNode: node, offset } = pos); } - } : undefined); - if (!preventScrollSupported) { - preventScrollSupported = false; - for (let i = 0; i < stack.length;) { - let elt = stack[i++], top = stack[i++], left = stack[i++]; - if (elt.scrollTop != top) - elt.scrollTop = top; - if (elt.scrollLeft != left) - elt.scrollLeft = left; + else if (doc.caretRangeFromPoint) { + let range = doc.caretRangeFromPoint(x, y); + if (range) { + ({ startContainer: node, startOffset: offset } = range); + if (browser.safari && isSuspiciousCaretResult(node, offset, x)) + node = undefined; + } } } + // No luck, do our own (potentially expensive) search + if (!node || !view.docView.dom.contains(node)) { + let line = LineView.find(view.docView, lineStart); + if (!line) + return yOffset > block.top + block.height / 2 ? block.to : block.from; + ({ node, offset } = domPosAtCoords(line.dom, x, y)); + } + return view.docView.posFromDOM(node, offset); } -let scratchRange; -function textRange(node, from, to = from) { - let range = scratchRange || (scratchRange = document.createRange()); - range.setEnd(node, to); - range.setStart(node, from); - return range; -} -function dispatchKey(elt, name, code) { - let options = { key: name, code: name, keyCode: code, which: code, cancelable: true }; - let down = new KeyboardEvent("keydown", options); - down.synthetic = true; - elt.dispatchEvent(down); - let up = new KeyboardEvent("keyup", options); - up.synthetic = true; - elt.dispatchEvent(up); - return down.defaultPrevented || up.defaultPrevented; -} -function getRoot(node) { - while (node) { - if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host)) - return node; - node = node.assignedSlot || node.parentNode; +function posAtCoordsImprecise(view, contentRect, block, x, y) { + let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth); + if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) { + let line = Math.floor((y - block.top) / view.defaultLineHeight); + into += line * view.viewState.heightOracle.lineLength; } - return null; + let content = view.state.sliceDoc(block.from, block.to); + return block.from + text.findColumn(content, into, view.state.tabSize); } -function clearAttributes(node) { - while (node.attributes.length) - node.removeAttributeNode(node.attributes[0]); +// In case of a high line height, Safari's caretRangeFromPoint treats +// the space between lines as belonging to the last character of the +// line before. This is used to detect such a result so that it can be +// ignored (issue #401). +function isSuspiciousCaretResult(node, offset, x) { + let len; + if (node.nodeType != 3 || offset != (len = node.nodeValue.length)) + return false; + for (let next = node.nextSibling; next; next = next.nextSibling) + if (next.nodeType != 1 || next.nodeName != "BR") + return false; + return textRange(node, len - 1, len).getBoundingClientRect().left > x; } - -class DOMPos { - constructor(node, offset, precise = true) { - this.node = node; - this.offset = offset; - this.precise = precise; +function moveToLineBoundary(view, start, forward, includeWrap) { + let line = view.state.doc.lineAt(start.head); + let coords = !includeWrap || !view.lineWrapping ? null + : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head); + if (coords) { + let editorRect = view.dom.getBoundingClientRect(); + let pos = view.posAtCoords({ x: forward == (view.textDirection == exports.Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1, + y: (coords.top + coords.bottom) / 2 }); + if (pos != null) + return state.EditorSelection.cursor(pos, forward ? -1 : 1); } - static before(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); } - static after(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); } + let lineView = LineView.find(view.docView, start.head); + let end = lineView ? (forward ? lineView.posAtEnd : lineView.posAtStart) : (forward ? line.to : line.from); + return state.EditorSelection.cursor(end, forward ? -1 : 1); } -const noChildren = []; -class ContentView { - constructor() { - this.parent = null; - this.dom = null; - this.dirty = 2 /* Node */; +function moveByChar(view, start, forward, by) { + let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line); + for (let cur = start, check = null;;) { + let next = moveVisually(line, spans, view.textDirection, cur, forward), char = movedOver; + if (!next) { + if (line.number == (forward ? view.state.doc.lines : 1)) + return cur; + char = "\n"; + line = view.state.doc.line(line.number + (forward ? 1 : -1)); + spans = view.bidiSpans(line); + next = state.EditorSelection.cursor(forward ? line.from : line.to); + } + if (!check) { + if (!by) + return next; + check = by(char); + } + else if (!check(char)) { + return cur; + } + cur = next; } - get editorView() { - if (!this.parent) - throw new Error("Accessing view in orphan content view"); - return this.parent.editorView; +} +function byGroup(view, pos, start) { + let categorize = view.state.charCategorizer(pos); + let cat = categorize(start); + return (next) => { + let nextCat = categorize(next); + if (cat == state.CharCategory.Space) + cat = nextCat; + return cat == nextCat; + }; +} +function moveVertically(view, start, forward, distance) { + let startPos = start.head, dir = forward ? 1 : -1; + if (startPos == (forward ? view.state.doc.length : 0)) + return state.EditorSelection.cursor(startPos); + let goal = start.goalColumn, startY; + let rect = view.contentDOM.getBoundingClientRect(); + let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop; + if (startCoords) { + if (goal == null) + goal = startCoords.left - rect.left; + startY = dir < 0 ? startCoords.top : startCoords.bottom; } - get overrideDOMText() { return null; } - get posAtStart() { - return this.parent ? this.parent.posBefore(this) : 0; + else { + let line = view.viewState.lineBlockAt(startPos - docTop); + if (goal == null) + goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from)); + startY = (dir < 0 ? line.top : line.bottom) + docTop; } - get posAtEnd() { - return this.posAtStart + this.length; + let resolvedGoal = rect.left + goal; + let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1); + for (let extra = 0;; extra += 10) { + let curY = startY + (dist + extra) * dir; + let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir); + if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos)) + return state.EditorSelection.cursor(pos, undefined, undefined, goal); } - posBefore(view) { - let pos = this.posAtStart; - for (let child of this.children) { - if (child == view) - return pos; - pos += child.length + child.breakAfter; +} +function skipAtoms(view, oldPos, pos) { + let atoms = view.pluginField(PluginField.atomicRanges); + for (;;) { + let moved = false; + for (let set of atoms) { + set.between(pos.from - 1, pos.from + 1, (from, to, value) => { + if (pos.from > from && pos.from < to) { + pos = oldPos.from > pos.from ? state.EditorSelection.cursor(from, 1) : state.EditorSelection.cursor(to, -1); + moved = true; + } + }); } - throw new RangeError("Invalid child in posBefore"); - } - posAfter(view) { - return this.posBefore(view) + view.length; + if (!moved) + return pos; } - // Will return a rectangle directly before (when side < 0), after - // (side > 0) or directly on (when the browser supports it) the - // given position. - coordsAt(_pos, _side) { return null; } - sync(track) { - if (this.dirty & 2 /* Node */) { - let parent = this.dom; - let pos = parent.firstChild; - for (let child of this.children) { - if (child.dirty) { - if (!child.dom && pos) { - let contentView = ContentView.get(pos); - if (!contentView || !contentView.parent && contentView.constructor == child.constructor) - child.reuseDOM(pos); - } - child.sync(track); - child.dirty = 0 /* Not */; - } - if (track && !track.written && track.node == parent && pos != child.dom) - track.written = true; - if (child.dom.parentNode == parent) { - while (pos && pos != child.dom) - pos = rm(pos); - pos = child.dom.nextSibling; - } - else { - parent.insertBefore(child.dom, pos); - } - } - if (pos && track && track.node == parent) - track.written = true; - while (pos) - pos = rm(pos); +} + +// This will also be where dragging info and such goes +class InputState { + constructor(view) { + this.lastKeyCode = 0; + this.lastKeyTime = 0; + // On iOS, some keys need to have their default behavior happen + // (after which we retroactively handle them and reset the DOM) to + // avoid messing up the virtual keyboard state. + this.pendingIOSKey = undefined; + this.lastSelectionOrigin = null; + this.lastSelectionTime = 0; + this.lastEscPress = 0; + this.lastContextMenu = 0; + this.scrollHandlers = []; + this.registeredEvents = []; + this.customHandlers = []; + // -1 means not in a composition. Otherwise, this counts the number + // of changes made during the composition. The count is used to + // avoid treating the start state of the composition, before any + // changes have been made, as part of the composition. + this.composing = -1; + // Tracks whether the next change should be marked as starting the + // composition (null means no composition, true means next is the + // first, false means first has already been marked for this + // composition) + this.compositionFirstChange = null; + this.compositionEndedAt = 0; + this.rapidCompositionStart = false; + this.mouseSelection = null; + for (let type in handlers) { + let handler = handlers[type]; + view.contentDOM.addEventListener(type, (event) => { + if (type == "keydown" && this.keydown(view, event)) + return; + if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event)) + return; + if (this.mustFlushObserver(event)) + view.observer.forceFlush(); + if (this.runCustomHandlers(type, view, event)) + event.preventDefault(); + else + handler(view, event); + }); + this.registeredEvents.push(type); } - else if (this.dirty & 1 /* Child */) { - for (let child of this.children) - if (child.dirty) { - child.sync(track); - child.dirty = 0 /* Not */; + this.notifiedFocused = view.hasFocus; + this.ensureHandlers(view); + // On Safari adding an input event handler somehow prevents an + // issue where the composition vanishes when you press enter. + if (browser.safari) + view.contentDOM.addEventListener("input", () => null); + } + setSelectionOrigin(origin) { + this.lastSelectionOrigin = origin; + this.lastSelectionTime = Date.now(); + } + ensureHandlers(view) { + let handlers = this.customHandlers = view.pluginField(domEventHandlers); + for (let set of handlers) { + for (let type in set.handlers) + if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") { + this.registeredEvents.push(type); + view.contentDOM.addEventListener(type, (event) => { + if (!eventBelongsToEditor(view, event)) + return; + if (this.runCustomHandlers(type, view, event)) + event.preventDefault(); + }); } } } - reuseDOM(_dom) { } - localPosFromDOM(node, offset) { - let after; - if (node == this.dom) { - after = this.dom.childNodes[offset]; - } - else { - let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1; - for (;;) { - let parent = node.parentNode; - if (parent == this.dom) - break; - if (bias == 0 && parent.firstChild != parent.lastChild) { - if (node == parent.firstChild) - bias = -1; - else - bias = 1; + runCustomHandlers(type, view, event) { + for (let set of this.customHandlers) { + let handler = set.handlers[type]; + if (handler) { + try { + if (handler.call(set.plugin, event, view) || event.defaultPrevented) + return true; + } + catch (e) { + logException(view.state, e); } - node = parent; } - if (bias < 0) - after = node; - else - after = node.nextSibling; - } - if (after == this.dom.firstChild) - return 0; - while (after && !ContentView.get(after)) - after = after.nextSibling; - if (!after) - return this.length; - for (let i = 0, pos = 0;; i++) { - let child = this.children[i]; - if (child.dom == after) - return pos; - pos += child.length + child.breakAfter; } + return false; } - domBoundsAround(from, to, offset = 0) { - let fromI = -1, fromStart = -1, toI = -1, toEnd = -1; - for (let i = 0, pos = offset, prevEnd = offset; i < this.children.length; i++) { - let child = this.children[i], end = pos + child.length; - if (pos < from && end > to) - return child.domBoundsAround(from, to, pos); - if (end >= from && fromI == -1) { - fromI = i; - fromStart = pos; - } - if (pos > to && child.dom.parentNode == this.dom) { - toI = i; - toEnd = prevEnd; - break; + runScrollHandlers(view, event) { + for (let set of this.customHandlers) { + let handler = set.handlers.scroll; + if (handler) { + try { + handler.call(set.plugin, event, view); + } + catch (e) { + logException(view.state, e); + } } - prevEnd = end; - pos = end + child.breakAfter; } - return { from: fromStart, to: toEnd < 0 ? offset + this.length : toEnd, - startDOM: (fromI ? this.children[fromI - 1].dom.nextSibling : null) || this.dom.firstChild, - endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null }; - } - markDirty(andParent = false) { - this.dirty |= 2 /* Node */; - this.markParentsDirty(andParent); } - markParentsDirty(childList) { - for (let parent = this.parent; parent; parent = parent.parent) { - if (childList) - parent.dirty |= 2 /* Node */; - if (parent.dirty & 1 /* Child */) - return; - parent.dirty |= 1 /* Child */; - childList = false; + keydown(view, event) { + // Must always run, even if a custom handler handled the event + this.lastKeyCode = event.keyCode; + this.lastKeyTime = Date.now(); + if (this.screenKeyEvent(view, event)) + return true; + // Chrome for Android usually doesn't fire proper key events, but + // occasionally does, usually surrounded by a bunch of complicated + // composition changes. When an enter or backspace key event is + // seen, hold off on handling DOM events for a bit, and then + // dispatch it. + if (browser.android && browser.chrome && !event.synthetic && + (event.keyCode == 13 || event.keyCode == 8)) { + view.observer.delayAndroidKey(event.key, event.keyCode); + return true; } - } - setParent(parent) { - if (this.parent != parent) { - this.parent = parent; - if (this.dirty) - this.markParentsDirty(true); + // Prevent the default behavior of Enter on iOS makes the + // virtual keyboard get stuck in the wrong (lowercase) + // state. So we let it go through, and then, in + // applyDOMChange, notify key handlers of it and reset to + // the state they produce. + let pending; + if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && + !(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) { + this.pendingIOSKey = pending; + setTimeout(() => this.flushIOSKey(view), 250); + return true; } + return false; } - setDOM(dom) { - if (this.dom) - this.dom.cmView = null; - this.dom = dom; - dom.cmView = this; - } - get rootView() { - for (let v = this;;) { - let parent = v.parent; - if (!parent) - return v; - v = parent; - } + flushIOSKey(view) { + let key = this.pendingIOSKey; + if (!key) + return false; + this.pendingIOSKey = undefined; + return dispatchKey(view.contentDOM, key.key, key.keyCode); } - replaceChildren(from, to, children = noChildren) { - this.markDirty(); - for (let i = from; i < to; i++) { - let child = this.children[i]; - if (child.parent == this) - child.destroy(); + ignoreDuringComposition(event) { + if (!/^key/.test(event.type)) + return false; + if (this.composing > 0) + return true; + // See https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/. + // On some input method editors (IMEs), the Enter key is used to + // confirm character selection. On Safari, when Enter is pressed, + // compositionend and keydown events are sometimes emitted in the + // wrong order. The key event should still be ignored, even when + // it happens after the compositionend event. + if (browser.safari && Date.now() - this.compositionEndedAt < 500) { + this.compositionEndedAt = 0; + return true; } - this.children.splice(from, to - from, ...children); - for (let i = 0; i < children.length; i++) - children[i].setParent(this); + return false; } - ignoreMutation(_rec) { return false; } - ignoreEvent(_event) { return false; } - childCursor(pos = this.length) { - return new ChildCursor(this.children, pos, this.children.length); + screenKeyEvent(view, event) { + let protectedTab = event.keyCode == 9 && Date.now() < this.lastEscPress + 2000; + if (event.keyCode == 27) + this.lastEscPress = Date.now(); + else if (modifierCodes.indexOf(event.keyCode) < 0) + this.lastEscPress = 0; + return protectedTab; } - childPos(pos, bias = 1) { - return this.childCursor().findPos(pos, bias); + mustFlushObserver(event) { + return (event.type == "keydown" && event.keyCode != 229) || + event.type == "compositionend" && !browser.ios; } - toString() { - let name = this.constructor.name.replace("View", ""); - return name + (this.children.length ? "(" + this.children.join() + ")" : - this.length ? "[" + (name == "Text" ? this.text : this.length) + "]" : "") + - (this.breakAfter ? "#" : ""); + startMouseSelection(mouseSelection) { + if (this.mouseSelection) + this.mouseSelection.destroy(); + this.mouseSelection = mouseSelection; } - static get(node) { return node.cmView; } - get isEditable() { return true; } - merge(from, to, source, hasStart, openStart, openEnd) { - return false; + update(update) { + if (this.mouseSelection) + this.mouseSelection.update(update); + if (update.transactions.length) + this.lastKeyCode = this.lastSelectionTime = 0; } - become(other) { return false; } - // When this is a zero-length view with a side, this should return a - // number <= 0 to indicate it is before its position, or a - // number > 0 when after its position. - getSide() { return 0; } destroy() { - this.parent = null; - } -} -ContentView.prototype.breakAfter = 0; -// Remove a DOM node and return its next sibling. -function rm(dom) { - let next = dom.nextSibling; - dom.parentNode.removeChild(dom); - return next; -} -class ChildCursor { - constructor(children, pos, i) { - this.children = children; - this.pos = pos; - this.i = i; - this.off = 0; - } - findPos(pos, bias = 1) { - for (;;) { - if (pos > this.pos || pos == this.pos && - (bias > 0 || this.i == 0 || this.children[this.i - 1].breakAfter)) { - this.off = pos - this.pos; - return this; - } - let next = this.children[--this.i]; - this.pos -= next.length + next.breakAfter; - } + if (this.mouseSelection) + this.mouseSelection.destroy(); } } -function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart, openStart, openEnd) { - let { children } = parent; - let before = children.length ? children[fromI] : null; - let last = insert.length ? insert[insert.length - 1] : null; - let breakAtEnd = last ? last.breakAfter : breakAtStart; - // Change within a single child - if (fromI == toI && before && !breakAtStart && !breakAtEnd && insert.length < 2 && - before.merge(fromOff, toOff, insert.length ? last : null, fromOff == 0, openStart, openEnd)) - return; - if (toI < children.length) { - let after = children[toI]; - // Make sure the end of the child after the update is preserved in `after` - if (after && toOff < after.length) { - // If we're splitting a child, separate part of it to avoid that - // being mangled when updating the child before the update. - if (fromI == toI) { - after = after.split(toOff); - toOff = 0; - } - // If the element after the replacement should be merged with - // the last replacing element, update `content` - if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) { - insert[insert.length - 1] = after; - } - else { - // Remove the start of the after element, if necessary, and - // add it to `content`. - if (toOff) - after.merge(0, toOff, null, false, 0, openEnd); - insert.push(after); - } - } - else if (after === null || after === void 0 ? void 0 : after.breakAfter) { - // The element at `toI` is entirely covered by this range. - // Preserve its line break, if any. - if (last) - last.breakAfter = 1; - else - breakAtStart = 1; - } - // Since we've handled the next element from the current elements - // now, make sure `toI` points after that. - toI++; - } - if (before) { - before.breakAfter = breakAtStart; - if (fromOff > 0) { - if (!breakAtStart && insert.length && before.merge(fromOff, before.length, insert[0], false, openStart, 0)) { - before.breakAfter = insert.shift().breakAfter; - } - else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) { - before.merge(fromOff, before.length, null, false, openStart, 0); - } - fromI++; +const PendingKeys = [ + { key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" }, + { key: "Enter", keyCode: 13, inputType: "insertParagraph" }, + { key: "Delete", keyCode: 46, inputType: "deleteContentForward" } +]; +// Key codes for modifier keys +const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225]; +class MouseSelection { + constructor(view, startEvent, style, mustSelect) { + this.view = view; + this.style = style; + this.mustSelect = mustSelect; + this.lastEvent = startEvent; + let doc = view.contentDOM.ownerDocument; + doc.addEventListener("mousemove", this.move = this.move.bind(this)); + doc.addEventListener("mouseup", this.up = this.up.bind(this)); + this.extend = startEvent.shiftKey; + this.multiple = view.state.facet(state.EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent); + this.dragMove = dragMovesSelection(view, startEvent); + this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false; + // When clicking outside of the selection, immediately apply the + // effect of starting the selection + if (this.dragging === false) { + startEvent.preventDefault(); + this.select(startEvent); } } - // Try to merge widgets on the boundaries of the replacement - while (fromI < toI && insert.length) { - if (children[toI - 1].become(insert[insert.length - 1])) { - toI--; - insert.pop(); - openEnd = insert.length ? 0 : openStart; - } - else if (children[fromI].become(insert[0])) { - fromI++; - insert.shift(); - openStart = insert.length ? 0 : openEnd; - } - else { - break; - } + move(event) { + if (event.buttons == 0) + return this.destroy(); + if (this.dragging !== false) + return; + this.select(this.lastEvent = event); } - if (!insert.length && fromI && toI < children.length && !children[fromI - 1].breakAfter && - children[toI].merge(0, 0, children[fromI - 1], false, openStart, openEnd)) - fromI--; - if (fromI < toI || insert.length) - parent.replaceChildren(fromI, toI, insert); -} -function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) { - let cur = parent.childCursor(); - let { i: toI, off: toOff } = cur.findPos(to, 1); - let { i: fromI, off: fromOff } = cur.findPos(from, -1); - let dLen = from - to; - for (let view of insert) - dLen += view.length; - parent.length += dLen; - replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd); -} - -let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" }; -let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } }; -const ie_edge = /Edge\/(\d+)/.exec(nav.userAgent); -const ie_upto10 = /MSIE \d/.test(nav.userAgent); -const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent); -const ie = !!(ie_upto10 || ie_11up || ie_edge); -const gecko = !ie && /gecko\/(\d+)/i.test(nav.userAgent); -const chrome = !ie && /Chrome\/(\d+)/.exec(nav.userAgent); -const webkit = "webkitFontSmoothing" in doc.documentElement.style; -const safari = !ie && /Apple Computer/.test(nav.vendor); -const ios = safari && (/Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2); -var browser = { - mac: ios || /Mac/.test(nav.platform), - windows: /Win/.test(nav.platform), - linux: /Linux|X11/.test(nav.platform), - ie, - ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0, - gecko, - gecko_version: gecko ? +(/Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0, - chrome: !!chrome, - chrome_version: chrome ? +chrome[1] : 0, - ios, - android: /Android\b/.test(nav.userAgent), - webkit, - safari, - webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0, - tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size" -}; - -const MaxJoinLen = 256; -class TextView extends ContentView { - constructor(text) { - super(); - this.text = text; + up(event) { + if (this.dragging == null) + this.select(this.lastEvent); + if (!this.dragging) + event.preventDefault(); + this.destroy(); } - get length() { return this.text.length; } - createDOM(textDOM) { - this.setDOM(textDOM || document.createTextNode(this.text)); + destroy() { + let doc = this.view.contentDOM.ownerDocument; + doc.removeEventListener("mousemove", this.move); + doc.removeEventListener("mouseup", this.up); + this.view.inputState.mouseSelection = null; } - sync(track) { - if (!this.dom) - this.createDOM(); - if (this.dom.nodeValue != this.text) { - if (track && track.node == this.dom) - track.written = true; - this.dom.nodeValue = this.text; - } + select(event) { + let selection = this.style.get(event, this.extend, this.multiple); + if (this.mustSelect || !selection.eq(this.view.state.selection) || + selection.main.assoc != this.view.state.selection.main.assoc) + this.view.dispatch({ + selection, + userEvent: "select.pointer", + scrollIntoView: true + }); + this.mustSelect = false; } - reuseDOM(dom) { - if (dom.nodeType == 3) - this.createDOM(dom); + update(update) { + if (update.docChanged && this.dragging) + this.dragging = this.dragging.map(update.changes); + if (this.style.update(update)) + setTimeout(() => this.select(this.lastEvent), 20); } - merge(from, to, source) { - if (source && (!(source instanceof TextView) || this.length - (to - from) + source.length > MaxJoinLen)) - return false; - this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to); - this.markDirty(); +} +function addsSelectionRange(view, event) { + let facet = view.state.facet(clickAddsSelectionRange); + return facet.length ? facet[0](event) : browser.mac ? event.metaKey : event.ctrlKey; +} +function dragMovesSelection(view, event) { + let facet = view.state.facet(dragMovesSelection$1); + return facet.length ? facet[0](event) : browser.mac ? !event.altKey : !event.ctrlKey; +} +function isInPrimarySelection(view, event) { + let { main } = view.state.selection; + if (main.empty) + return false; + // On boundary clicks, check whether the coordinates are inside the + // selection's client rectangles + let sel = getSelection(view.root); + if (sel.rangeCount == 0) return true; + let rects = sel.getRangeAt(0).getClientRects(); + for (let i = 0; i < rects.length; i++) { + let rect = rects[i]; + if (rect.left <= event.clientX && rect.right >= event.clientX && + rect.top <= event.clientY && rect.bottom >= event.clientY) + return true; } - split(from) { - let result = new TextView(this.text.slice(from)); - this.text = this.text.slice(0, from); - this.markDirty(); - return result; - } - localPosFromDOM(node, offset) { - return node == this.dom ? offset : offset ? this.text.length : 0; - } - domAtPos(pos) { return new DOMPos(this.dom, pos); } - domBoundsAround(_from, _to, offset) { - return { from: offset, to: offset + this.length, startDOM: this.dom, endDOM: this.dom.nextSibling }; - } - coordsAt(pos, side) { - return textCoords(this.dom, pos, side); - } + return false; +} +function eventBelongsToEditor(view, event) { + if (!event.bubbles) + return true; + if (event.defaultPrevented) + return false; + for (let node = event.target, cView; node != view.contentDOM; node = node.parentNode) + if (!node || node.nodeType == 11 || ((cView = ContentView.get(node)) && cView.ignoreEvent(event))) + return false; + return true; +} +const handlers = Object.create(null); +// This is very crude, but unfortunately both these browsers _pretend_ +// that they have a clipboard API—all the objects and methods are +// there, they just don't work, and they are hard to test. +const brokenClipboardAPI = (browser.ie && browser.ie_version < 15) || + (browser.ios && browser.webkit_version < 604); +function capturePaste(view) { + let parent = view.dom.parentNode; + if (!parent) + return; + let target = parent.appendChild(document.createElement("textarea")); + target.style.cssText = "position: fixed; left: -10000px; top: 10px"; + target.focus(); + setTimeout(() => { + view.focus(); + target.remove(); + doPaste(view, target.value); + }, 50); } -class MarkView extends ContentView { - constructor(mark, children = [], length = 0) { - super(); - this.mark = mark; - this.children = children; - this.length = length; - for (let ch of children) - ch.setParent(this); +function doPaste(view, input) { + let { state: state$1 } = view, changes, i = 1, text = state$1.toText(input); + let byLine = text.lines == state$1.selection.ranges.length; + let linewise = lastLinewiseCopy != null && state$1.selection.ranges.every(r => r.empty) && lastLinewiseCopy == text.toString(); + if (linewise) { + let lastLine = -1; + changes = state$1.changeByRange(range => { + let line = state$1.doc.lineAt(range.from); + if (line.from == lastLine) + return { range }; + lastLine = line.from; + let insert = state$1.toText((byLine ? text.line(i++).text : input) + state$1.lineBreak); + return { changes: { from: line.from, insert }, + range: state.EditorSelection.cursor(range.from + insert.length) }; + }); } - setAttrs(dom) { - clearAttributes(dom); - if (this.mark.class) - dom.className = this.mark.class; - if (this.mark.attrs) - for (let name in this.mark.attrs) - dom.setAttribute(name, this.mark.attrs[name]); - return dom; + else if (byLine) { + changes = state$1.changeByRange(range => { + let line = text.line(i++); + return { changes: { from: range.from, to: range.to, insert: line.text }, + range: state.EditorSelection.cursor(range.from + line.length) }; + }); } - reuseDOM(node) { - if (node.nodeName == this.mark.tagName.toUpperCase()) { - this.setDOM(node); - this.dirty |= 4 /* Attrs */ | 2 /* Node */; - } + else { + changes = state$1.replaceSelection(text); } - sync(track) { - if (!this.dom) - this.setDOM(this.setAttrs(document.createElement(this.mark.tagName))); - else if (this.dirty & 4 /* Attrs */) - this.setAttrs(this.dom); - super.sync(track); + view.dispatch(changes, { + userEvent: "input.paste", + scrollIntoView: true + }); +} +handlers.keydown = (view, event) => { + view.inputState.setSelectionOrigin("select"); +}; +let lastTouch = 0; +handlers.touchstart = (view, e) => { + lastTouch = Date.now(); + view.inputState.setSelectionOrigin("select.pointer"); +}; +handlers.touchmove = view => { + view.inputState.setSelectionOrigin("select.pointer"); +}; +handlers.mousedown = (view, event) => { + view.observer.flush(); + if (lastTouch > Date.now() - 2000 && getClickType(event) == 1) + return; // Ignore touch interaction + let style = null; + for (let makeStyle of view.state.facet(mouseSelectionStyle)) { + style = makeStyle(view, event); + if (style) + break; } - merge(from, to, source, _hasStart, openStart, openEnd) { - if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) || - (from && openStart <= 0) || (to < this.length && openEnd <= 0))) - return false; - mergeChildrenInto(this, from, to, source ? source.children : [], openStart - 1, openEnd - 1); - this.markDirty(); - return true; + if (!style && event.button == 0) + style = basicMouseSelection(view, event); + if (style) { + let mustFocus = view.root.activeElement != view.contentDOM; + if (mustFocus) + view.observer.ignore(() => focusPreventScroll(view.contentDOM)); + view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus)); } - split(from) { - let result = [], off = 0, detachFrom = -1, i = 0; - for (let elt of this.children) { - let end = off + elt.length; - if (end > from) - result.push(off < from ? elt.split(from - off) : elt); - if (detachFrom < 0 && off >= from) - detachFrom = i; - off = end; - i++; - } - let length = this.length - from; - this.length = from; - if (detachFrom > -1) { - this.children.length = detachFrom; - this.markDirty(); - } - return new MarkView(this.mark, result, length); +}; +function rangeForClick(view, pos, bias, type) { + if (type == 1) { // Single click + return state.EditorSelection.cursor(pos, bias); } - domAtPos(pos) { - return inlineDOMAtPos(this.dom, this.children, pos); + else if (type == 2) { // Double click + return groupAt(view.state, pos, bias); } - coordsAt(pos, side) { - return coordsInChildren(this, pos, side); + else { // Triple click + let visual = LineView.find(view.docView, pos), line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos); + let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to; + if (to < view.state.doc.length && to == line.to) + to++; + return state.EditorSelection.range(from, to); } } -function textCoords(text, pos, side) { - let length = text.nodeValue.length; - if (pos > length) - pos = length; - let from = pos, to = pos, flatten = 0; - if (pos == 0 && side < 0 || pos == length && side >= 0) { - if (!(browser.chrome || browser.gecko)) { // These browsers reliably return valid rectangles for empty ranges - if (pos) { - from--; - flatten = 1; - } // FIXME this is wrong in RTL text +let insideY = (y, rect) => y >= rect.top && y <= rect.bottom; +let inside = (x, y, rect) => insideY(y, rect) && x >= rect.left && x <= rect.right; +// Try to determine, for the given coordinates, associated with the +// given position, whether they are related to the element before or +// the element after the position. +function findPositionSide(view, pos, x, y) { + let line = LineView.find(view.docView, pos); + if (!line) + return 1; + let off = pos - line.posAtStart; + // Line boundaries point into the line + if (off == 0) + return 1; + if (off == line.length) + return -1; + // Positions on top of an element point at that element + let before = line.coordsAt(off, -1); + if (before && inside(x, y, before)) + return -1; + let after = line.coordsAt(off, 1); + if (after && inside(x, y, after)) + return 1; + // This is probably a line wrap point. Pick before if the point is + // beside it. + return before && insideY(y, before) ? -1 : 1; +} +function queryPos(view, event) { + let pos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false); + return { pos, bias: findPositionSide(view, pos, event.clientX, event.clientY) }; +} +const BadMouseDetail = browser.ie && browser.ie_version <= 11; +let lastMouseDown = null, lastMouseDownCount = 0, lastMouseDownTime = 0; +function getClickType(event) { + if (!BadMouseDetail) + return event.detail; + let last = lastMouseDown, lastTime = lastMouseDownTime; + lastMouseDown = event; + lastMouseDownTime = Date.now(); + return lastMouseDownCount = !last || (lastTime > Date.now() - 400 && Math.abs(last.clientX - event.clientX) < 2 && + Math.abs(last.clientY - event.clientY) < 2) ? (lastMouseDownCount + 1) % 3 : 1; +} +function basicMouseSelection(view, event) { + let start = queryPos(view, event), type = getClickType(event); + let startSel = view.state.selection; + let last = start, lastEvent = event; + return { + update(update) { + if (update.docChanged) { + if (start) + start.pos = update.changes.mapPos(start.pos); + startSel = startSel.map(update.changes); + lastEvent = null; + } + }, + get(event, extend, multiple) { + let cur; + if (lastEvent && event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY) + cur = last; else { - to++; - flatten = -1; + cur = last = queryPos(view, event); + lastEvent = event; + } + if (!cur || !start) + return startSel; + let range = rangeForClick(view, cur.pos, cur.bias, type); + if (start.pos != cur.pos && !extend) { + let startRange = rangeForClick(view, start.pos, start.bias, type); + let from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to); + range = from < range.from ? state.EditorSelection.range(from, to) : state.EditorSelection.range(to, from); } + if (extend) + return startSel.replaceRange(startSel.main.extend(range.from, range.to)); + else if (multiple) + return startSel.addRange(range); + else + return state.EditorSelection.create([range]); } - } - else { - if (side < 0) - from--; - else - to++; - } - let rects = textRange(text, from, to).getClientRects(); - if (!rects.length) - return Rect0; - let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1]; - if (browser.safari && !flatten && rect.width == 0) - rect = Array.prototype.find.call(rects, r => r.width) || rect; - return flatten ? flattenRect(rect, flatten < 0) : rect || null; + }; } -// Also used for collapsed ranges that don't have a placeholder widget! -class WidgetView extends ContentView { - constructor(widget, length, side) { - super(); - this.widget = widget; - this.length = length; - this.side = side; +handlers.dragstart = (view, event) => { + let { selection: { main } } = view.state; + let { mouseSelection } = view.inputState; + if (mouseSelection) + mouseSelection.dragging = main; + if (event.dataTransfer) { + event.dataTransfer.setData("Text", view.state.sliceDoc(main.from, main.to)); + event.dataTransfer.effectAllowed = "copyMove"; } - static create(widget, length, side) { - return new (widget.customView || WidgetView)(widget, length, side); +}; +function dropText(view, event, text, direct) { + if (!text) + return; + let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false); + event.preventDefault(); + let { mouseSelection } = view.inputState; + let del = direct && mouseSelection && mouseSelection.dragging && mouseSelection.dragMove ? + { from: mouseSelection.dragging.from, to: mouseSelection.dragging.to } : null; + let ins = { from: dropPos, insert: text }; + let changes = view.state.changes(del ? [del, ins] : ins); + view.focus(); + view.dispatch({ + changes, + selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) }, + userEvent: del ? "move.drop" : "input.drop" + }); +} +handlers.drop = (view, event) => { + if (!event.dataTransfer) + return; + if (view.state.readOnly) + return event.preventDefault(); + let files = event.dataTransfer.files; + if (files && files.length) { // For a file drop, read the file's text. + event.preventDefault(); + let text = Array(files.length), read = 0; + let finishFile = () => { + if (++read == files.length) + dropText(view, event, text.filter(s => s != null).join(view.state.lineBreak), false); + }; + for (let i = 0; i < files.length; i++) { + let reader = new FileReader; + reader.onerror = finishFile; + reader.onload = () => { + if (!/[\x00-\x08\x0e-\x1f]{2}/.test(reader.result)) + text[i] = reader.result; + finishFile(); + }; + reader.readAsText(files[i]); + } } - split(from) { - let result = WidgetView.create(this.widget, this.length - from, this.side); - this.length -= from; - return result; + else { + dropText(view, event, event.dataTransfer.getData("Text"), true); } - sync() { - if (!this.dom || !this.widget.updateDOM(this.dom)) { - this.setDOM(this.widget.toDOM(this.editorView)); - this.dom.contentEditable = "false"; - } +}; +handlers.paste = (view, event) => { + if (view.state.readOnly) + return event.preventDefault(); + view.observer.flush(); + let data = brokenClipboardAPI ? null : event.clipboardData; + if (data) { + doPaste(view, data.getData("text/plain")); + event.preventDefault(); } - getSide() { return this.side; } - merge(from, to, source, hasStart, openStart, openEnd) { - if (source && (!(source instanceof WidgetView) || !this.widget.compare(source.widget) || - from > 0 && openStart <= 0 || to < this.length && openEnd <= 0)) - return false; - this.length = from + (source ? source.length : 0) + (this.length - to); - return true; + else { + capturePaste(view); } - become(other) { - if (other.length == this.length && other instanceof WidgetView && other.side == this.side) { - if (this.widget.constructor == other.widget.constructor) { - if (!this.widget.eq(other.widget)) - this.markDirty(true); - this.widget = other.widget; - return true; +}; +function captureCopy(view, text) { + // The extra wrapper is somehow necessary on IE/Edge to prevent the + // content from being mangled when it is put onto the clipboard + let parent = view.dom.parentNode; + if (!parent) + return; + let target = parent.appendChild(document.createElement("textarea")); + target.style.cssText = "position: fixed; left: -10000px; top: 10px"; + target.value = text; + target.focus(); + target.selectionEnd = text.length; + target.selectionStart = 0; + setTimeout(() => { + target.remove(); + view.focus(); + }, 50); +} +function copiedRange(state) { + let content = [], ranges = [], linewise = false; + for (let range of state.selection.ranges) + if (!range.empty) { + content.push(state.sliceDoc(range.from, range.to)); + ranges.push(range); + } + if (!content.length) { + // Nothing selected, do a line-wise copy + let upto = -1; + for (let { from } of state.selection.ranges) { + let line = state.doc.lineAt(from); + if (line.number > upto) { + content.push(line.text); + ranges.push({ from: line.from, to: Math.min(state.doc.length, line.to + 1) }); } + upto = line.number; } - return false; + linewise = true; } - ignoreMutation() { return true; } - ignoreEvent(event) { return this.widget.ignoreEvent(event); } - get overrideDOMText() { - if (this.length == 0) - return text.Text.empty; - let top = this; - while (top.parent) - top = top.parent; - let view = top.editorView, text$1 = view && view.state.doc, start = this.posAtStart; - return text$1 ? text$1.slice(start, start + this.length) : text.Text.empty; + return { text: content.join(state.lineBreak), ranges, linewise }; +} +let lastLinewiseCopy = null; +handlers.copy = handlers.cut = (view, event) => { + let { text, ranges, linewise } = copiedRange(view.state); + if (!text && !linewise) + return; + lastLinewiseCopy = linewise ? text : null; + let data = brokenClipboardAPI ? null : event.clipboardData; + if (data) { + event.preventDefault(); + data.clearData(); + data.setData("text/plain", text); } - domAtPos(pos) { - return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length); + else { + captureCopy(view, text); } - domBoundsAround() { return null; } - coordsAt(pos, side) { - let rects = this.dom.getClientRects(), rect = null; - if (!rects.length) - return Rect0; - for (let i = pos > 0 ? rects.length - 1 : 0;; i += (pos > 0 ? -1 : 1)) { - rect = rects[i]; - if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom) - break; + if (event.type == "cut" && !view.state.readOnly) + view.dispatch({ + changes: ranges, + scrollIntoView: true, + userEvent: "delete.cut" + }); +}; +handlers.focus = handlers.blur = view => { + setTimeout(() => { + if (view.hasFocus != view.inputState.notifiedFocused) + view.update([]); + }, 10); +}; +handlers.beforeprint = view => { + view.viewState.printing = true; + view.requestMeasure(); + setTimeout(() => { + view.viewState.printing = false; + view.requestMeasure(); + }, 2000); +}; +function forceClearComposition(view, rapid) { + if (view.docView.compositionDeco.size) { + view.inputState.rapidCompositionStart = rapid; + try { + view.update([]); + } + finally { + view.inputState.rapidCompositionStart = false; } - return (pos == 0 && side > 0 || pos == this.length && side <= 0) ? rect : flattenRect(rect, pos == 0); - } - get isEditable() { return false; } - destroy() { - super.destroy(); - if (this.dom) - this.widget.destroy(this.dom); - } -} -class CompositionView extends WidgetView { - domAtPos(pos) { return new DOMPos(this.widget.text, pos); } - sync() { this.setDOM(this.widget.toDOM()); } - localPosFromDOM(node, offset) { - return !offset ? 0 : node.nodeType == 3 ? Math.min(offset, this.length) : this.length; } - ignoreMutation() { return false; } - get overrideDOMText() { return null; } - coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); } - get isEditable() { return true; } } -// Use two characters on Android, to prevent Chrome from closing the -// virtual keyboard when backspacing after a widget (#602). -const ZeroWidthSpace = browser.android ? "\u200b\u200b" : "\u200b"; -// These are drawn around uneditable widgets to avoid a number of -// browser bugs that show up when the cursor is directly next to -// uneditable inline content. -class WidgetBufferView extends ContentView { - constructor(side) { - super(); - this.side = side; - } - get length() { return 0; } - merge() { return false; } - become(other) { - return other instanceof WidgetBufferView && other.side == this.side; - } - split() { return new WidgetBufferView(this.side); } - sync() { - if (!this.dom) - this.setDOM(document.createTextNode(ZeroWidthSpace)); - else if (this.dirty && this.dom.nodeValue != ZeroWidthSpace) - this.dom.nodeValue = ZeroWidthSpace; - } - getSide() { return this.side; } - domAtPos(pos) { return DOMPos.before(this.dom); } - localPosFromDOM() { return 0; } - domBoundsAround() { return null; } - coordsAt(pos) { - let rects = clientRectsFor(this.dom); - return rects[rects.length - 1] || null; +handlers.compositionstart = handlers.compositionupdate = view => { + if (view.inputState.compositionFirstChange == null) + view.inputState.compositionFirstChange = true; + if (view.inputState.composing < 0) { + // FIXME possibly set a timeout to clear it again on Android + view.inputState.composing = 0; + if (view.docView.compositionDeco.size) { + view.observer.flush(); + forceClearComposition(view, true); + } } - get overrideDOMText() { - return text.Text.of([this.dom.nodeValue.replace(/\u200b/g, "")]); +}; +handlers.compositionend = view => { + view.inputState.composing = -1; + view.inputState.compositionEndedAt = Date.now(); + view.inputState.compositionFirstChange = null; + setTimeout(() => { + if (view.inputState.composing < 0) + forceClearComposition(view, false); + }, 50); +}; +handlers.contextmenu = view => { + view.inputState.lastContextMenu = Date.now(); +}; +handlers.beforeinput = (view, event) => { + var _a; + // Because Chrome Android doesn't fire useful key events, use + // beforeinput to detect backspace (and possibly enter and delete, + // but those usually don't even seem to fire beforeinput events at + // the moment) and fake a key event for it. + // + // (preventDefault on beforeinput, though supported in the spec, + // seems to do nothing at all on Chrome). + let pending; + if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) { + view.observer.delayAndroidKey(pending.key, pending.keyCode); + if (pending.key == "Backspace" || pending.key == "Delete") { + let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0; + setTimeout(() => { + var _a; + // Backspacing near uneditable nodes on Chrome Android sometimes + // closes the virtual keyboard. This tries to crudely detect + // that and refocus to get it back. + if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) { + view.contentDOM.blur(); + view.focus(); + } + }, 100); + } } -} -TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren; -function inlineDOMAtPos(dom, children, pos) { - let i = 0; - for (let off = 0; i < children.length; i++) { - let child = children[i], end = off + child.length; - if (end == off && child.getSide() <= 0) - continue; - if (pos > off && pos < end && child.dom.parentNode == dom) - return child.domAtPos(pos - off); - if (pos <= off) - break; - off = end; +}; + +const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"]; +class HeightOracle { + constructor() { + this.doc = text.Text.empty; + this.lineWrapping = false; + this.direction = exports.Direction.LTR; + this.heightSamples = {}; + this.lineHeight = 14; + this.charWidth = 7; + this.lineLength = 30; + // Used to track, during updateHeight, if any actual heights changed + this.heightChanged = false; } - for (; i > 0; i--) { - let before = children[i - 1].dom; - if (before.parentNode == dom) - return DOMPos.after(before); + heightForGap(from, to) { + let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1; + if (this.lineWrapping) + lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength); + return this.lineHeight * lines; } - return new DOMPos(dom, 0); -} -// Assumes `view`, if a mark view, has precisely 1 child. -function joinInlineInto(parent, view, open) { - let last, { children } = parent; - if (open > 0 && view instanceof MarkView && children.length && - (last = children[children.length - 1]) instanceof MarkView && last.mark.eq(view.mark)) { - joinInlineInto(last, view.children[0], open - 1); + heightForLine(length) { + if (!this.lineWrapping) + return this.lineHeight; + let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / (this.lineLength - 5))); + return lines * this.lineHeight; } - else { - children.push(view); - view.setParent(parent); + setDoc(doc) { this.doc = doc; return this; } + mustRefreshForStyle(whiteSpace, direction) { + return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction; } - parent.length += view.length; -} -function coordsInChildren(view, pos, side) { - for (let off = 0, i = 0; i < view.children.length; i++) { - let child = view.children[i], end = off + child.length, next; - if ((side <= 0 || end == view.length || child.getSide() > 0 ? end >= pos : end > pos) && - (pos < end || i + 1 == view.children.length || (next = view.children[i + 1]).length || next.getSide() > 0)) { - let flatten = 0; - if (end == off) { - if (child.getSide() <= 0) - continue; - flatten = side = -child.getSide(); + mustRefreshForHeights(lineHeights) { + let newHeight = false; + for (let i = 0; i < lineHeights.length; i++) { + let h = lineHeights[i]; + if (h < 0) { + i++; + } + else if (!this.heightSamples[Math.floor(h * 10)]) { // Round to .1 pixels + newHeight = true; + this.heightSamples[Math.floor(h * 10)] = true; } - let rect = child.coordsAt(pos - off, side); - return flatten && rect ? flattenRect(rect, side < 0) : rect; } - off = end; + return newHeight; } - let last = view.dom.lastChild; - if (!last) - return view.dom.getBoundingClientRect(); - let rects = clientRectsFor(last); - return rects[rects.length - 1] || null; -} - -function combineAttrs(source, target) { - for (let name in source) { - if (name == "class" && target.class) - target.class += " " + source.class; - else if (name == "style" && target.style) - target.style += ";" + source.style; - else - target[name] = source[name]; + refresh(whiteSpace, direction, lineHeight, charWidth, lineLength, knownHeights) { + let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1; + let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || + this.lineWrapping != lineWrapping || + this.direction != direction; + this.lineWrapping = lineWrapping; + this.direction = direction; + this.lineHeight = lineHeight; + this.charWidth = charWidth; + this.lineLength = lineLength; + if (changed) { + this.heightSamples = {}; + for (let i = 0; i < knownHeights.length; i++) { + let h = knownHeights[i]; + if (h < 0) + i++; + else + this.heightSamples[Math.floor(h * 10)] = true; + } + } + return changed; } - return target; } -function attrsEq(a, b) { - if (a == b) - return true; - if (!a || !b) - return false; - let keysA = Object.keys(a), keysB = Object.keys(b); - if (keysA.length != keysB.length) - return false; - for (let key of keysA) { - if (keysB.indexOf(key) == -1 || a[key] !== b[key]) - return false; +// This object is used by `updateHeight` to make DOM measurements +// arrive at the right nides. The `heights` array is a sequence of +// block heights, starting from position `from`. +class MeasuredHeights { + constructor(from, heights) { + this.from = from; + this.heights = heights; + this.index = 0; } - return true; -} -function updateAttrs(dom, prev, attrs) { - if (prev) - for (let name in prev) - if (!(attrs && name in attrs)) - dom.removeAttribute(name); - if (attrs) - for (let name in attrs) - if (!(prev && prev[name] == attrs[name])) - dom.setAttribute(name, attrs[name]); + get more() { return this.index < this.heights.length; } } - /** -Widgets added to the content are described by subclasses of this -class. Using a description object like that makes it possible to -delay creating of the DOM structure for a widget until it is -needed, and to avoid redrawing widgets even when the decorations -that define them are recreated. +Record used to represent information about a block-level element +in the editor view. */ -class WidgetType { - /** - Compare this instance to another instance of the same type. - (TypeScript can't express this, but only instances of the same - specific class will be passed to this method.) This is used to - avoid redrawing widgets when they are replaced by a new - decoration of the same type. The default implementation just - returns `false`, which will cause new instances of the widget to - always be redrawn. - */ - eq(_widget) { return false; } - /** - Update a DOM element created by a widget of the same type (but - different, non-`eq` content) to reflect this widget. May return - true to indicate that it could update, false to indicate it - couldn't (in which case the widget will be redrawn). The default - implementation just returns false. - */ - updateDOM(_dom) { return false; } - /** - @internal - */ - compare(other) { - return this == other || this.constructor == other.constructor && this.eq(other); - } - /** - The estimated height this widget will have, to be used when - estimating the height of content that hasn't been drawn. May - return -1 to indicate you don't know. The default implementation - returns -1. - */ - get estimatedHeight() { return -1; } - /** - Can be used to configure which kinds of events inside the widget - should be ignored by the editor. The default is to ignore all - events. - */ - ignoreEvent(_event) { return true; } +class BlockInfo { /** @internal */ - get customView() { return null; } - /** - This is called when the an instance of the widget is removed - from the editor view. - */ - destroy(_dom) { } -} -/** -The different types of blocks that can occur in an editor view. -*/ -exports.BlockType = void 0; -(function (BlockType) { + constructor( /** - A line of text. + The start of the element in the document. */ - BlockType[BlockType["Text"] = 0] = "Text"; + from, /** - A block widget associated with the position after it. + The length of the element. */ - BlockType[BlockType["WidgetBefore"] = 1] = "WidgetBefore"; + length, /** - A block widget associated with the position before it. + The top position of the element (relative to the top of the + document). */ - BlockType[BlockType["WidgetAfter"] = 2] = "WidgetAfter"; + top, /** - A block widget [replacing](https://codemirror.net/6/docs/ref/#view.Decoration^replace) a range of content. + Its height. */ - BlockType[BlockType["WidgetRange"] = 3] = "WidgetRange"; -})(exports.BlockType || (exports.BlockType = {})); -/** -A decoration provides information on how to draw or style a piece -of content. You'll usually use it wrapped in a -[`Range`](https://codemirror.net/6/docs/ref/#rangeset.Range), which adds a start and end position. -*/ -class Decoration extends rangeset.RangeValue { + height, /** - @internal + The type of element this is. When querying lines, this may be + an array of all the blocks that make up the line. */ - constructor( + type) { + this.from = from; + this.length = length; + this.top = top; + this.height = height; + this.type = type; + } /** - @internal + The end of the element as a document position. */ - startSide, + get to() { return this.from + this.length; } /** - @internal + The bottom position of the element. */ - endSide, + get bottom() { return this.top + this.height; } /** @internal */ - widget, - /** - The config object used to create this decoration. You can - include additional properties in there to store metadata about - your decoration. - */ - spec) { - super(); - this.startSide = startSide; - this.endSide = endSide; - this.widget = widget; - this.spec = spec; + join(other) { + let detail = (Array.isArray(this.type) ? this.type : [this]) + .concat(Array.isArray(other.type) ? other.type : [other]); + return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail); } /** - @internal - */ - get heightRelevant() { return false; } - /** - Create a mark decoration, which influences the styling of the - content in its range. Nested mark decorations will cause nested - DOM elements to be created. Nesting order is determined by - precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) or - (below the facet-provided decorations) [view - plugin](https://codemirror.net/6/docs/ref/#view.PluginSpec.decorations). Such elements are split - on line boundaries and on the boundaries of higher-precedence - decorations. + FIXME remove on next breaking release @internal */ - static mark(spec) { - return new MarkDecoration(spec); + moveY(offset) { + return !offset ? this : new BlockInfo(this.from, this.length, this.top + offset, this.height, Array.isArray(this.type) ? this.type.map(b => b.moveY(offset)) : this.type); } - /** - Create a widget decoration, which adds an element at the given - position. - */ - static widget(spec) { - let side = spec.side || 0, block = !!spec.block; - side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */); - return new PointDecoration(spec, side, side, block, spec.widget || null, false); +} +var QueryType; +(function (QueryType) { + QueryType[QueryType["ByPos"] = 0] = "ByPos"; + QueryType[QueryType["ByHeight"] = 1] = "ByHeight"; + QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight"; +})(QueryType || (QueryType = {})); +const Epsilon = 1e-3; +class HeightMap { + constructor(length, // The number of characters covered + height, // Height of this part of the document + flags = 2 /* Outdated */) { + this.length = length; + this.height = height; + this.flags = flags; } - /** - Create a replace decoration which replaces the given range with - a widget, or simply hides it. - */ - static replace(spec) { - let block = !!spec.block; - let { start, end } = getInclusive(spec, block); - let startSide = (start ? (block ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 400000000 /* NonIncStart */) - 1; - let endSide = (end ? (block ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -500000000 /* NonIncEnd */) + 1; - return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true); + get outdated() { return (this.flags & 2 /* Outdated */) > 0; } + set outdated(value) { this.flags = (value ? 2 /* Outdated */ : 0) | (this.flags & ~2 /* Outdated */); } + setHeight(oracle, height) { + if (this.height != height) { + if (Math.abs(this.height - height) > Epsilon) + oracle.heightChanged = true; + this.height = height; + } + } + // Base case is to replace a leaf node, which simply builds a tree + // from the new nodes and returns that (HeightMapBranch and + // HeightMapGap override this to actually use from/to) + replace(_from, _to, nodes) { + return HeightMap.of(nodes); + } + // Again, these are base cases, and are overridden for branch and gap nodes. + decomposeLeft(_to, result) { result.push(this); } + decomposeRight(_from, result) { result.push(this); } + applyChanges(decorations, oldDoc, oracle, changes) { + let me = this; + for (let i = changes.length - 1; i >= 0; i--) { + let { fromA, toA, fromB, toB } = changes[i]; + let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0); + let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oldDoc, 0, 0); + toB += end.to - toA; + toA = end.to; + while (i > 0 && start.from <= changes[i - 1].toA) { + fromA = changes[i - 1].fromA; + fromB = changes[i - 1].fromB; + i--; + if (fromA < start.from) + start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0); + } + fromB += start.from - fromA; + fromA = start.from; + let nodes = NodeBuilder.build(oracle, decorations, fromB, toB); + me = me.replace(fromA, toA, nodes); + } + return me.updateHeight(oracle, 0); + } + static empty() { return new HeightMapText(0, 0); } + // nodes uses null values to indicate the position of line breaks. + // There are never line breaks at the start or end of the array, or + // two line breaks next to each other, and the array isn't allowed + // to be empty (same restrictions as return value from the builder). + static of(nodes) { + if (nodes.length == 1) + return nodes[0]; + let i = 0, j = nodes.length, before = 0, after = 0; + for (;;) { + if (i == j) { + if (before > after * 2) { + let split = nodes[i - 1]; + if (split.break) + nodes.splice(--i, 1, split.left, null, split.right); + else + nodes.splice(--i, 1, split.left, split.right); + j += 1 + split.break; + before -= split.size; + } + else if (after > before * 2) { + let split = nodes[j]; + if (split.break) + nodes.splice(j, 1, split.left, null, split.right); + else + nodes.splice(j, 1, split.left, split.right); + j += 2 + split.break; + after -= split.size; + } + else { + break; + } + } + else if (before < after) { + let next = nodes[i++]; + if (next) + before += next.size; + } + else { + let next = nodes[--j]; + if (next) + after += next.size; + } + } + let brk = 0; + if (nodes[i - 1] == null) { + brk = 1; + i--; + } + else if (nodes[i] == null) { + brk = 1; + j++; + } + return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j))); + } +} +HeightMap.prototype.size = 1; +class HeightMapBlock extends HeightMap { + constructor(length, height, type) { + super(length, height); + this.type = type; + } + blockAt(_height, _doc, top, offset) { + return new BlockInfo(offset, this.length, top, this.height, this.type); + } + lineAt(_value, _type, doc, top, offset) { + return this.blockAt(0, doc, top, offset); + } + forEachLine(_from, _to, doc, top, offset, f) { + f(this.blockAt(0, doc, top, offset)); + } + updateHeight(oracle, offset = 0, _force = false, measured) { + if (measured && measured.from <= offset && measured.more) + this.setHeight(oracle, measured.heights[measured.index++]); + this.outdated = false; + return this; + } + toString() { return `block(${this.length})`; } +} +class HeightMapText extends HeightMapBlock { + constructor(length, height) { + super(length, height, exports.BlockType.Text); + this.collapsed = 0; // Amount of collapsed content in the line + this.widgetHeight = 0; // Maximum inline widget height + } + replace(_from, _to, nodes) { + let node = nodes[0]; + if (nodes.length == 1 && (node instanceof HeightMapText || node instanceof HeightMapGap && (node.flags & 4 /* SingleLine */)) && + Math.abs(this.length - node.length) < 10) { + if (node instanceof HeightMapGap) + node = new HeightMapText(node.length, this.height); + else + node.height = this.height; + if (!this.outdated) + node.outdated = false; + return node; + } + else { + return HeightMap.of(nodes); + } + } + updateHeight(oracle, offset = 0, force = false, measured) { + if (measured && measured.from <= offset && measured.more) + this.setHeight(oracle, measured.heights[measured.index++]); + else if (force || this.outdated) + this.setHeight(oracle, Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed))); + this.outdated = false; + return this; + } + toString() { + return `line(${this.length}${this.collapsed ? -this.collapsed : ""}${this.widgetHeight ? ":" + this.widgetHeight : ""})`; + } +} +class HeightMapGap extends HeightMap { + constructor(length) { super(length, 0); } + lines(doc, offset) { + let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number; + return { firstLine, lastLine, lineHeight: this.height / (lastLine - firstLine + 1) }; + } + blockAt(height, doc, top, offset) { + let { firstLine, lastLine, lineHeight } = this.lines(doc, offset); + let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / lineHeight))); + let { from, length } = doc.line(firstLine + line); + return new BlockInfo(from, length, top + lineHeight * line, lineHeight, exports.BlockType.Text); + } + lineAt(value, type, doc, top, offset) { + if (type == QueryType.ByHeight) + return this.blockAt(value, doc, top, offset); + if (type == QueryType.ByPosNoHeight) { + let { from, to } = doc.lineAt(value); + return new BlockInfo(from, to - from, 0, 0, exports.BlockType.Text); + } + let { firstLine, lineHeight } = this.lines(doc, offset); + let { from, length, number } = doc.lineAt(value); + return new BlockInfo(from, length, top + lineHeight * (number - firstLine), lineHeight, exports.BlockType.Text); } - /** - Create a line decoration, which can add DOM attributes to the - line starting at the given position. - */ - static line(spec) { - return new LineDecoration(spec); + forEachLine(from, to, doc, top, offset, f) { + let { firstLine, lineHeight } = this.lines(doc, offset); + for (let pos = Math.max(from, offset), end = Math.min(offset + this.length, to); pos <= end;) { + let line = doc.lineAt(pos); + if (pos == from) + top += lineHeight * (line.number - firstLine); + f(new BlockInfo(line.from, line.length, top, lineHeight, exports.BlockType.Text)); + top += lineHeight; + pos = line.to + 1; + } } - /** - Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given - decorated range or ranges. If the ranges aren't already sorted, - pass `true` for `sort` to make the library sort them for you. - */ - static set(of, sort = false) { - return rangeset.RangeSet.of(of, sort); + replace(from, to, nodes) { + let after = this.length - to; + if (after > 0) { + let last = nodes[nodes.length - 1]; + if (last instanceof HeightMapGap) + nodes[nodes.length - 1] = new HeightMapGap(last.length + after); + else + nodes.push(null, new HeightMapGap(after - 1)); + } + if (from > 0) { + let first = nodes[0]; + if (first instanceof HeightMapGap) + nodes[0] = new HeightMapGap(from + first.length); + else + nodes.unshift(new HeightMapGap(from - 1), null); + } + return HeightMap.of(nodes); } - /** - @internal - */ - hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; } -} -/** -The empty set of decorations. -*/ -Decoration.none = rangeset.RangeSet.empty; -class MarkDecoration extends Decoration { - constructor(spec) { - let { start, end } = getInclusive(spec); - super(start ? -1 /* InlineIncStart */ : 400000000 /* NonIncStart */, end ? 1 /* InlineIncEnd */ : -500000000 /* NonIncEnd */, null, spec); - this.tagName = spec.tagName || "span"; - this.class = spec.class || ""; - this.attrs = spec.attributes || null; + decomposeLeft(to, result) { + result.push(new HeightMapGap(to - 1), null); } - eq(other) { - return this == other || - other instanceof MarkDecoration && - this.tagName == other.tagName && - this.class == other.class && - attrsEq(this.attrs, other.attrs); + decomposeRight(from, result) { + result.push(null, new HeightMapGap(this.length - from - 1)); } - range(from, to = from) { - if (from >= to) - throw new RangeError("Mark decorations may not be empty"); - return super.range(from, to); + updateHeight(oracle, offset = 0, force = false, measured) { + let end = offset + this.length; + if (measured && measured.from <= offset + this.length && measured.more) { + // Fill in part of this gap with measured lines. We know there + // can't be widgets or collapsed ranges in those lines, because + // they would already have been added to the heightmap (gaps + // only contain plain text). + let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1; + let wasChanged = oracle.heightChanged; + if (measured.from > offset) + nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset)); + while (pos <= end && measured.more) { + let len = oracle.doc.lineAt(pos).length; + if (nodes.length) + nodes.push(null); + let height = measured.heights[measured.index++]; + if (singleHeight == -1) + singleHeight = height; + else if (Math.abs(height - singleHeight) >= Epsilon) + singleHeight = -2; + let line = new HeightMapText(len, height); + line.outdated = false; + nodes.push(line); + pos += len + 1; + } + if (pos <= end) + nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos)); + let result = HeightMap.of(nodes); + oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon || + Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon; + return result; + } + else if (force || this.outdated) { + this.setHeight(oracle, oracle.heightForGap(offset, offset + this.length)); + this.outdated = false; + } + return this; } + toString() { return `gap(${this.length})`; } } -MarkDecoration.prototype.point = false; -class LineDecoration extends Decoration { - constructor(spec) { - super(-200000000 /* Line */, -200000000 /* Line */, null, spec); +class HeightMapBranch extends HeightMap { + constructor(left, brk, right) { + super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Outdated */ : 0)); + this.left = left; + this.right = right; + this.size = left.size + right.size; } - eq(other) { - return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes); + get break() { return this.flags & 1 /* Break */; } + blockAt(height, doc, top, offset) { + let mid = top + this.left.height; + return height < mid ? this.left.blockAt(height, doc, top, offset) + : this.right.blockAt(height, doc, mid, offset + this.left.length + this.break); } - range(from, to = from) { - if (to != from) - throw new RangeError("Line decoration ranges must be zero-length"); - return super.range(from, to); + lineAt(value, type, doc, top, offset) { + let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break; + let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset; + let base = left ? this.left.lineAt(value, type, doc, top, offset) + : this.right.lineAt(value, type, doc, rightTop, rightOffset); + if (this.break || (left ? base.to < rightOffset : base.from > rightOffset)) + return base; + let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos; + if (left) + return base.join(this.right.lineAt(rightOffset, subQuery, doc, rightTop, rightOffset)); + else + return this.left.lineAt(rightOffset, subQuery, doc, top, offset).join(base); } -} -LineDecoration.prototype.mapMode = state.MapMode.TrackBefore; -LineDecoration.prototype.point = true; -class PointDecoration extends Decoration { - constructor(spec, startSide, endSide, block, widget, isReplace) { - super(startSide, endSide, widget, spec); - this.block = block; - this.isReplace = isReplace; - this.mapMode = !block ? state.MapMode.TrackDel : startSide <= 0 ? state.MapMode.TrackBefore : state.MapMode.TrackAfter; + forEachLine(from, to, doc, top, offset, f) { + let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break; + if (this.break) { + if (from < rightOffset) + this.left.forEachLine(from, to, doc, top, offset, f); + if (to >= rightOffset) + this.right.forEachLine(from, to, doc, rightTop, rightOffset, f); + } + else { + let mid = this.lineAt(rightOffset, QueryType.ByPos, doc, top, offset); + if (from < mid.from) + this.left.forEachLine(from, mid.from - 1, doc, top, offset, f); + if (mid.to >= from && mid.from <= to) + f(mid); + if (to > mid.to) + this.right.forEachLine(mid.to + 1, to, doc, rightTop, rightOffset, f); + } } - // Only relevant when this.block == true - get type() { - return this.startSide < this.endSide ? exports.BlockType.WidgetRange - : this.startSide <= 0 ? exports.BlockType.WidgetBefore : exports.BlockType.WidgetAfter; + replace(from, to, nodes) { + let rightStart = this.left.length + this.break; + if (to < rightStart) + return this.balanced(this.left.replace(from, to, nodes), this.right); + if (from > this.left.length) + return this.balanced(this.left, this.right.replace(from - rightStart, to - rightStart, nodes)); + let result = []; + if (from > 0) + this.decomposeLeft(from, result); + let left = result.length; + for (let node of nodes) + result.push(node); + if (from > 0) + mergeGaps(result, left - 1); + if (to < this.length) { + let right = result.length; + this.decomposeRight(to, result); + mergeGaps(result, right); + } + return HeightMap.of(result); } - get heightRelevant() { return this.block || !!this.widget && this.widget.estimatedHeight >= 5; } - eq(other) { - return other instanceof PointDecoration && - widgetsEq(this.widget, other.widget) && - this.block == other.block && - this.startSide == other.startSide && this.endSide == other.endSide; + decomposeLeft(to, result) { + let left = this.left.length; + if (to <= left) + return this.left.decomposeLeft(to, result); + result.push(this.left); + if (this.break) { + left++; + if (to >= left) + result.push(null); + } + if (to > left) + this.right.decomposeLeft(to - left, result); } - range(from, to = from) { - if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0))) - throw new RangeError("Invalid range for replacement decoration"); - if (!this.isReplace && to != from) - throw new RangeError("Widget decorations can only have zero-length ranges"); - return super.range(from, to); + decomposeRight(from, result) { + let left = this.left.length, right = left + this.break; + if (from >= right) + return this.right.decomposeRight(from - right, result); + if (from < left) + this.left.decomposeRight(from, result); + if (this.break && from < right) + result.push(null); + result.push(this.right); } + balanced(left, right) { + if (left.size > 2 * right.size || right.size > 2 * left.size) + return HeightMap.of(this.break ? [left, null, right] : [left, right]); + this.left = left; + this.right = right; + this.height = left.height + right.height; + this.outdated = left.outdated || right.outdated; + this.size = left.size + right.size; + this.length = left.length + this.break + right.length; + return this; + } + updateHeight(oracle, offset = 0, force = false, measured) { + let { left, right } = this, rightStart = offset + left.length + this.break, rebalance = null; + if (measured && measured.from <= offset + left.length && measured.more) + rebalance = left = left.updateHeight(oracle, offset, force, measured); + else + left.updateHeight(oracle, offset, force); + if (measured && measured.from <= rightStart + right.length && measured.more) + rebalance = right = right.updateHeight(oracle, rightStart, force, measured); + else + right.updateHeight(oracle, rightStart, force); + if (rebalance) + return this.balanced(left, right); + this.height = this.left.height + this.right.height; + this.outdated = false; + return this; + } + toString() { return this.left + (this.break ? " " : "-") + this.right; } } -PointDecoration.prototype.point = true; -function getInclusive(spec, block = false) { - let { inclusiveStart: start, inclusiveEnd: end } = spec; - if (start == null) - start = spec.inclusive; - if (end == null) - end = spec.inclusive; - return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block }; -} -function widgetsEq(a, b) { - return a == b || !!(a && b && a.compare(b)); -} -function addRange(from, to, ranges, margin = 0) { - let last = ranges.length - 1; - if (last >= 0 && ranges[last] + margin >= from) - ranges[last] = Math.max(ranges[last], to); - else - ranges.push(from, to); +function mergeGaps(nodes, around) { + let before, after; + if (nodes[around] == null && + (before = nodes[around - 1]) instanceof HeightMapGap && + (after = nodes[around + 1]) instanceof HeightMapGap) + nodes.splice(around - 1, 3, new HeightMapGap(before.length + 1 + after.length)); } - -class LineView extends ContentView { - constructor() { - super(...arguments); - this.children = []; - this.length = 0; - this.prevAttrs = undefined; - this.attrs = null; - this.breakAfter = 0; +const relevantWidgetHeight = 5; +class NodeBuilder { + constructor(pos, oracle) { + this.pos = pos; + this.oracle = oracle; + this.nodes = []; + this.lineStart = -1; + this.lineEnd = -1; + this.covering = null; + this.writtenTo = pos; } - // Consumes source - merge(from, to, source, hasStart, openStart, openEnd) { - if (source) { - if (!(source instanceof LineView)) - return false; - if (!this.dom) - source.transferDOM(this); // Reuse source.dom when appropriate - } - if (hasStart) - this.setDeco(source ? source.attrs : null); - mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd); - return true; + get isCovered() { + return this.covering && this.nodes[this.nodes.length - 1] == this.covering; } - split(at) { - let end = new LineView; - end.breakAfter = this.breakAfter; - if (this.length == 0) - return end; - let { i, off } = this.childPos(at); - if (off) { - end.append(this.children[i].split(off), 0); - this.children[i].merge(off, this.children[i].length, null, false, 0, 0); - i++; + span(_from, to) { + if (this.lineStart > -1) { + let end = Math.min(to, this.lineEnd), last = this.nodes[this.nodes.length - 1]; + if (last instanceof HeightMapText) + last.length += end - this.pos; + else if (end > this.pos || !this.isCovered) + this.nodes.push(new HeightMapText(end - this.pos, -1)); + this.writtenTo = end; + if (to > end) { + this.nodes.push(null); + this.writtenTo++; + this.lineStart = -1; + } } - for (let j = i; j < this.children.length; j++) - end.append(this.children[j], 0); - while (i > 0 && this.children[i - 1].length == 0) - this.children[--i].destroy(); - this.children.length = i; - this.markDirty(); - this.length = at; - return end; - } - transferDOM(other) { - if (!this.dom) - return; - other.setDOM(this.dom); - other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs; - this.prevAttrs = undefined; - this.dom = null; + this.pos = to; } - setDeco(attrs) { - if (!attrsEq(this.attrs, attrs)) { - if (this.dom) { - this.prevAttrs = this.attrs; - this.markDirty(); + point(from, to, deco) { + if (from < to || deco.heightRelevant) { + let height = deco.widget ? deco.widget.estimatedHeight : 0; + if (height < 0) + height = this.oracle.lineHeight; + let len = to - from; + if (deco.block) { + this.addBlock(new HeightMapBlock(len, height, deco.type)); } - this.attrs = attrs; + else if (len || height >= relevantWidgetHeight) { + this.addLineDeco(height, len); + } + } + else if (to > from) { + this.span(from, to); } + if (this.lineEnd > -1 && this.lineEnd < this.pos) + this.lineEnd = this.oracle.doc.lineAt(this.pos).to; } - append(child, openStart) { - joinInlineInto(this, child, openStart); + enterLine() { + if (this.lineStart > -1) + return; + let { from, to } = this.oracle.doc.lineAt(this.pos); + this.lineStart = from; + this.lineEnd = to; + if (this.writtenTo < from) { + if (this.writtenTo < from - 1 || this.nodes[this.nodes.length - 1] == null) + this.nodes.push(this.blankContent(this.writtenTo, from - 1)); + this.nodes.push(null); + } + if (this.pos > from) + this.nodes.push(new HeightMapText(this.pos - from, -1)); + this.writtenTo = this.pos; } - // Only called when building a line view in ContentBuilder - addLineDeco(deco) { - let attrs = deco.spec.attributes, cls = deco.spec.class; - if (attrs) - this.attrs = combineAttrs(attrs, this.attrs || {}); - if (cls) - this.attrs = combineAttrs({ class: cls }, this.attrs || {}); + blankContent(from, to) { + let gap = new HeightMapGap(to - from); + if (this.oracle.doc.lineAt(from).to == to) + gap.flags |= 4 /* SingleLine */; + return gap; } - domAtPos(pos) { - return inlineDOMAtPos(this.dom, this.children, pos); + ensureLine() { + this.enterLine(); + let last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null; + if (last instanceof HeightMapText) + return last; + let line = new HeightMapText(0, -1); + this.nodes.push(line); + return line; } - reuseDOM(node) { - if (node.nodeName == "DIV") { - this.setDOM(node); - this.dirty |= 4 /* Attrs */ | 2 /* Node */; - } + addBlock(block) { + this.enterLine(); + if (block.type == exports.BlockType.WidgetAfter && !this.isCovered) + this.ensureLine(); + this.nodes.push(block); + this.writtenTo = this.pos = this.pos + block.length; + if (block.type != exports.BlockType.WidgetBefore) + this.covering = block; } - sync(track) { - var _a; - if (!this.dom) { - this.setDOM(document.createElement("div")); - this.dom.className = "cm-line"; - this.prevAttrs = this.attrs ? null : undefined; - } - else if (this.dirty & 4 /* Attrs */) { - clearAttributes(this.dom); - this.dom.className = "cm-line"; - this.prevAttrs = this.attrs ? null : undefined; - } - if (this.prevAttrs !== undefined) { - updateAttrs(this.dom, this.prevAttrs, this.attrs); - this.dom.classList.add("cm-line"); - this.prevAttrs = undefined; - } - super.sync(track); - let last = this.dom.lastChild; - while (last && ContentView.get(last) instanceof MarkView) - last = last.lastChild; - if (!last || - last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false && - (!browser.ios || !this.children.some(ch => ch instanceof TextView))) { - let hack = document.createElement("BR"); - hack.cmIgnore = true; - this.dom.appendChild(hack); - } + addLineDeco(height, length) { + let line = this.ensureLine(); + line.length += length; + line.collapsed += length; + line.widgetHeight = Math.max(line.widgetHeight, height); + this.writtenTo = this.pos = this.pos + length; } - measureTextSize() { - if (this.children.length == 0 || this.length > 20) - return null; - let totalWidth = 0; - for (let child of this.children) { - if (!(child instanceof TextView)) - return null; - let rects = clientRectsFor(child.dom); - if (rects.length != 1) - return null; - totalWidth += rects[0].width; + finish(from) { + let last = this.nodes.length == 0 ? null : this.nodes[this.nodes.length - 1]; + if (this.lineStart > -1 && !(last instanceof HeightMapText) && !this.isCovered) + this.nodes.push(new HeightMapText(0, -1)); + else if (this.writtenTo < this.pos || last == null) + this.nodes.push(this.blankContent(this.writtenTo, this.pos)); + let pos = from; + for (let node of this.nodes) { + if (node instanceof HeightMapText) + node.updateHeight(this.oracle, pos); + pos += node ? node.length : 1; } - return { lineHeight: this.dom.getBoundingClientRect().height, - charWidth: totalWidth / this.length }; + return this.nodes; } - coordsAt(pos, side) { - return coordsInChildren(this, pos, side); + // Always called with a region that on both sides either stretches + // to a line break or the end of the document. + // The returned array uses null to indicate line breaks, but never + // starts or ends in a line break, or has multiple line breaks next + // to each other. + static build(oracle, decorations, from, to) { + let builder = new NodeBuilder(from, oracle); + rangeset.RangeSet.spans(decorations, from, to, builder, 0); + return builder.finish(from); } - become(_other) { return false; } - get type() { return exports.BlockType.Text; } - static find(docView, pos) { - for (let i = 0, off = 0; i < docView.children.length; i++) { - let block = docView.children[i], end = off + block.length; - if (end >= pos) { - if (block instanceof LineView) - return block; - if (end > pos) - break; +} +function heightRelevantDecoChanges(a, b, diff) { + let comp = new DecorationComparator; + rangeset.RangeSet.compare(a, b, diff, comp, 0); + return comp.changes; +} +class DecorationComparator { + constructor() { + this.changes = []; + } + compareRange() { } + comparePoint(from, to, a, b) { + if (from < to || a && a.heightRelevant || b && b.heightRelevant) + addRange(from, to, this.changes, 5); + } +} + +function visiblePixelRange(dom, paddingTop) { + let rect = dom.getBoundingClientRect(); + let left = Math.max(0, rect.left), right = Math.min(innerWidth, rect.right); + let top = Math.max(0, rect.top), bottom = Math.min(innerHeight, rect.bottom); + let body = dom.ownerDocument.body; + for (let parent = dom.parentNode; parent && parent != body;) { + if (parent.nodeType == 1) { + let elt = parent; + let style = window.getComputedStyle(elt); + if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) && + style.overflow != "visible") { + let parentRect = elt.getBoundingClientRect(); + left = Math.max(left, parentRect.left); + right = Math.min(right, parentRect.right); + top = Math.max(top, parentRect.top); + bottom = Math.min(bottom, parentRect.bottom); } - off = end + block.breakAfter; + parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode; + } + else if (parent.nodeType == 11) { // Shadow root + parent = parent.host; + } + else { + break; } - return null; } + return { left: left - rect.left, right: Math.max(left, right) - rect.left, + top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) }; } -class BlockWidgetView extends ContentView { - constructor(widget, length, type) { - super(); - this.widget = widget; - this.length = length; - this.type = type; - this.breakAfter = 0; +// Line gaps are placeholder widgets used to hide pieces of overlong +// lines within the viewport, as a kludge to keep the editor +// responsive when a ridiculously long line is loaded into it. +class LineGap { + constructor(from, to, size) { + this.from = from; + this.to = to; + this.size = size; } - merge(from, to, source, _takeDeco, openStart, openEnd) { - if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) || - from > 0 && openStart <= 0 || to < this.length && openEnd <= 0)) + static same(a, b) { + if (a.length != b.length) return false; - this.length = from + (source ? source.length : 0) + (this.length - to); + for (let i = 0; i < a.length; i++) { + let gA = a[i], gB = b[i]; + if (gA.from != gB.from || gA.to != gB.to || gA.size != gB.size) + return false; + } return true; } - domAtPos(pos) { - return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length); + draw(wrapping) { + return Decoration.replace({ widget: new LineGapWidget(this.size, wrapping) }).range(this.from, this.to); } - split(at) { - let len = this.length - at; - this.length = at; - let end = new BlockWidgetView(this.widget, len, this.type); - end.breakAfter = this.breakAfter; - return end; +} +class LineGapWidget extends WidgetType { + constructor(size, vertical) { + super(); + this.size = size; + this.vertical = vertical; } - get children() { return noChildren; } - sync() { - if (!this.dom || !this.widget.updateDOM(this.dom)) { - this.setDOM(this.widget.toDOM(this.editorView)); - this.dom.contentEditable = "false"; + eq(other) { return other.size == this.size && other.vertical == this.vertical; } + toDOM() { + let elt = document.createElement("div"); + if (this.vertical) { + elt.style.height = this.size + "px"; } - } - get overrideDOMText() { - return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : state.Text.empty; - } - domBoundsAround() { return null; } - become(other) { - if (other instanceof BlockWidgetView && other.type == this.type && - other.widget.constructor == this.widget.constructor) { - if (!other.widget.eq(this.widget)) - this.markDirty(true); - this.widget = other.widget; - this.length = other.length; - this.breakAfter = other.breakAfter; - return true; + else { + elt.style.width = this.size + "px"; + elt.style.height = "2px"; + elt.style.display = "inline-block"; } - return false; - } - ignoreMutation() { return true; } - ignoreEvent(event) { return this.widget.ignoreEvent(event); } - destroy() { - super.destroy(); - if (this.dom) - this.widget.destroy(this.dom); + return elt; } + get estimatedHeight() { return this.vertical ? this.size : -1; } } - -class ContentBuilder { - constructor(doc, pos, end, disallowBlockEffectsBelow) { - this.doc = doc; - this.pos = pos; - this.end = end; - this.disallowBlockEffectsBelow = disallowBlockEffectsBelow; - this.content = []; - this.curLine = null; - this.breakAtStart = 0; - this.pendingBuffer = 0 /* No */; - // Set to false directly after a widget that covers the position after it - this.atCursorPos = true; - this.openStart = -1; - this.openEnd = -1; - this.text = ""; - this.textOff = 0; - this.cursor = doc.iter(); - this.skip = pos; - } - posCovered() { - if (this.content.length == 0) - return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos; - let last = this.content[this.content.length - 1]; - return !last.breakAfter && !(last instanceof BlockWidgetView && last.type == exports.BlockType.WidgetBefore); - } - getLine() { - if (!this.curLine) { - this.content.push(this.curLine = new LineView); - this.atCursorPos = true; - } - return this.curLine; +class ViewState { + constructor(state) { + this.state = state; + // These are contentDOM-local coordinates + this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 }; + this.inView = true; + this.paddingTop = 0; + this.paddingBottom = 0; + this.contentDOMWidth = 0; + this.contentDOMHeight = 0; + this.editorHeight = 0; + this.editorWidth = 0; + this.heightOracle = new HeightOracle; + // See VP.MaxDOMHeight + this.scaler = IdScaler; + this.scrollTarget = null; + // Briefly set to true when printing, to disable viewport limiting + this.printing = false; + // Flag set when editor content was redrawn, so that the next + // measure stage knows it must read DOM layout + this.mustMeasureContent = true; + this.visibleRanges = []; + // Cursor 'assoc' is only significant when the cursor is on a line + // wrap point, where it must stick to the character that it is + // associated with. Since browsers don't provide a reasonable + // interface to set or query this, when a selection is set that + // might cause this to be significant, this flag is set. The next + // measure phase will check whether the cursor is on a line-wrapping + // boundary and, if so, reset it to make sure it is positioned in + // the right place. + this.mustEnforceCursorAssoc = false; + this.heightMap = HeightMap.empty().applyChanges(state.facet(decorations), text.Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]); + this.viewport = this.getViewport(0, null); + this.updateViewportLines(); + this.updateForViewport(); + this.lineGaps = this.ensureLineGaps([]); + this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false))); + this.computeVisibleRanges(); } - flushBuffer(active) { - if (this.pendingBuffer) { - this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length); - this.pendingBuffer = 0 /* No */; + updateForViewport() { + let viewports = [this.viewport], { main } = this.state.selection; + for (let i = 0; i <= 1; i++) { + let pos = i ? main.head : main.anchor; + if (!viewports.some(({ from, to }) => pos >= from && pos <= to)) { + let { from, to } = this.lineBlockAt(pos); + viewports.push(new Viewport(from, to)); + } } + this.viewports = viewports.sort((a, b) => a.from - b.from); + this.scaler = this.heightMap.height <= 7000000 /* MaxDOMHeight */ ? IdScaler : + new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports); } - addBlockWidget(view) { - this.flushBuffer([]); - this.curLine = null; - this.content.push(view); + updateViewportLines() { + this.viewportLines = []; + this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => { + this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler)); + }); } - finish(openEnd) { - if (!openEnd) - this.flushBuffer([]); - else - this.pendingBuffer = 0 /* No */; - if (!this.posCovered()) - this.getLine(); + update(update, scrollTarget = null) { + let prev = this.state; + this.state = update.state; + let newDeco = this.state.facet(decorations); + let contentChanges = update.changedRanges; + let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(update.startState.facet(decorations), newDeco, update ? update.changes : state.ChangeSet.empty(this.state.doc.length))); + let prevHeight = this.heightMap.height; + this.heightMap = this.heightMap.applyChanges(newDeco, prev.doc, this.heightOracle.setDoc(this.state.doc), heightChanges); + if (this.heightMap.height != prevHeight) + update.flags |= 2 /* Height */; + let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport; + if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) || + !this.viewportIsAppropriate(viewport)) + viewport = this.getViewport(0, scrollTarget); + let updateLines = !update.changes.empty || (update.flags & 2 /* Height */) || + viewport.from != this.viewport.from || viewport.to != this.viewport.to; + this.viewport = viewport; + this.updateForViewport(); + if (updateLines) + this.updateViewportLines(); + if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */) + this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes))); + update.flags |= this.computeVisibleRanges(); + if (scrollTarget) + this.scrollTarget = scrollTarget; + if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping && + update.state.selection.main.empty && update.state.selection.main.assoc) + this.mustEnforceCursorAssoc = true; } - buildText(length, active, openStart) { - while (length > 0) { - if (this.textOff == this.text.length) { - let { value, lineBreak, done } = this.cursor.next(this.skip); - this.skip = 0; - if (done) - throw new Error("Ran out of text content when drawing inline views"); - if (lineBreak) { - if (!this.posCovered()) - this.getLine(); - if (this.content.length) - this.content[this.content.length - 1].breakAfter = 1; - else - this.breakAtStart = 1; - this.flushBuffer([]); - this.curLine = null; - length--; - continue; - } - else { - this.text = value; - this.textOff = 0; + measure(view) { + let dom = view.contentDOM, style = window.getComputedStyle(dom); + let oracle = this.heightOracle; + let whiteSpace = style.whiteSpace, direction = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR; + let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction); + let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight; + let result = 0, bias = 0; + if (measureContent) { + this.mustMeasureContent = false; + this.contentDOMHeight = dom.clientHeight; + // Vertical padding + let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0; + if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) { + result |= 8 /* Geometry */; + this.paddingTop = paddingTop; + this.paddingBottom = paddingBottom; + } + } + // Pixel viewport + let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 } : visiblePixelRange(dom, this.paddingTop); + let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom; + this.pixelViewport = pixelViewport; + let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left; + if (inView != this.inView) { + this.inView = inView; + if (inView) + measureContent = true; + } + if (!this.inView) + return 0; + let contentWidth = dom.clientWidth; + if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight || + this.editorWidth != view.scrollDOM.clientWidth) { + this.contentDOMWidth = contentWidth; + this.editorHeight = view.scrollDOM.clientHeight; + this.editorWidth = view.scrollDOM.clientWidth; + result |= 8 /* Geometry */; + } + if (measureContent) { + let lineHeights = view.docView.measureVisibleLineHeights(); + if (oracle.mustRefreshForHeights(lineHeights)) + refresh = true; + if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) { + let { lineHeight, charWidth } = view.docView.measureTextSize(); + refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights); + if (refresh) { + view.docView.minWidth = 0; + result |= 8 /* Geometry */; } } - let take = Math.min(this.text.length - this.textOff, length, 512 /* Chunk */); - this.flushBuffer(active.slice(0, openStart)); - this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart); - this.atCursorPos = true; - this.textOff += take; - length -= take; - openStart = 0; + if (dTop > 0 && dBottom > 0) + bias = Math.max(dTop, dBottom); + else if (dTop < 0 && dBottom < 0) + bias = Math.min(dTop, dBottom); + oracle.heightChanged = false; + this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(this.viewport.from, lineHeights)); + if (oracle.heightChanged) + result |= 2 /* Height */; + } + let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) || + this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to); + if (viewportChange) + this.viewport = this.getViewport(bias, this.scrollTarget); + this.updateForViewport(); + if ((result & 2 /* Height */) || viewportChange) + this.updateViewportLines(); + if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */) + this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps)); + result |= this.computeVisibleRanges(); + if (this.mustEnforceCursorAssoc) { + this.mustEnforceCursorAssoc = false; + // This is done in the read stage, because moving the selection + // to a line end is going to trigger a layout anyway, so it + // can't be a pure write. It should be rare that it does any + // writing. + view.docView.enforceCursorAssoc(); } + return result; } - span(from, to, active, openStart) { - this.buildText(to - from, active, openStart); - this.pos = to; - if (this.openStart < 0) - this.openStart = openStart; + get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top); } + get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom); } + getViewport(bias, scrollTarget) { + // This will divide VP.Margin between the top and the + // bottom, depending on the bias (the change in viewport position + // since the last update). It'll hold a number between 0 and 1 + let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* Margin */ / 2)); + let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this; + let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).to); + // If scrollTarget is given, make sure the viewport includes that position + if (scrollTarget) { + let { head } = scrollTarget.range, viewHeight = this.editorHeight; + if (head < viewport.from || head > viewport.to) { + let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos; + if (scrollTarget.y == "center") + topPos = (block.top + block.bottom) / 2 - viewHeight / 2; + else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from) + topPos = block.top; + else + topPos = block.bottom - viewHeight; + viewport = new Viewport(map.lineAt(topPos - 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to); + } + } + return viewport; } - point(from, to, deco, active, openStart) { - let len = to - from; - if (deco instanceof PointDecoration) { - if (deco.block) { - let { type } = deco; - if (type == exports.BlockType.WidgetAfter && !this.posCovered()) - this.getLine(); - this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type)); + mapViewport(viewport, changes) { + let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1); + return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0).to); + } + // Checks if a given viewport covers the visible part of the + // document and not too much beyond that. + viewportIsAppropriate({ from, to }, bias = 0) { + if (!this.inView) + return true; + let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0); + let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0); + let { visibleTop, visibleBottom } = this; + return (from == 0 || top <= visibleTop - Math.max(10 /* MinCoverMargin */, Math.min(-bias, 250 /* MaxCoverMargin */))) && + (to == this.state.doc.length || + bottom >= visibleBottom + Math.max(10 /* MinCoverMargin */, Math.min(bias, 250 /* MaxCoverMargin */))) && + (top > visibleTop - 2 * 1000 /* Margin */ && bottom < visibleBottom + 2 * 1000 /* Margin */); + } + mapLineGaps(gaps, changes) { + if (!gaps.length || changes.empty) + return gaps; + let mapped = []; + for (let gap of gaps) + if (!changes.touchesRange(gap.from, gap.to)) + mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size)); + return mapped; + } + // Computes positions in the viewport where the start or end of a + // line should be hidden, trying to reuse existing line gaps when + // appropriate to avoid unneccesary redraws. + // Uses crude character-counting for the positioning and sizing, + // since actual DOM coordinates aren't always available and + // predictable. Relies on generous margins (see LG.Margin) to hide + // the artifacts this might produce from the user. + ensureLineGaps(current) { + let gaps = []; + // This won't work at all in predominantly right-to-left text. + if (this.heightOracle.direction != exports.Direction.LTR) + return gaps; + for (let line of this.viewportLines) { + if (line.length < 4000 /* DoubleMargin */) + continue; + let structure = lineStructure(line.from, line.to, this.state); + if (structure.total < 4000 /* DoubleMargin */) + continue; + let viewFrom, viewTo; + if (this.heightOracle.lineWrapping) { + let marginHeight = (2000 /* Margin */ / this.heightOracle.lineLength) * this.heightOracle.lineHeight; + viewFrom = findPosition(structure, (this.visibleTop - line.top - marginHeight) / line.height); + viewTo = findPosition(structure, (this.visibleBottom - line.top + marginHeight) / line.height); } else { - let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide); - let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0); - let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0); - let line = this.getLine(); - if (this.pendingBuffer == 2 /* IfCursor */ && !cursorBefore) - this.pendingBuffer = 0 /* No */; - this.flushBuffer(active); - if (cursorBefore) { - line.append(wrapMarks(new WidgetBufferView(1), active), openStart); - openStart = active.length + Math.max(0, openStart - active.length); - } - line.append(wrapMarks(view, active), openStart); - this.atCursorPos = cursorAfter; - this.pendingBuffer = !cursorAfter ? 0 /* No */ : from < to ? 1 /* Yes */ : 2 /* IfCursor */; + let totalWidth = structure.total * this.heightOracle.charWidth; + let marginWidth = 2000 /* Margin */ * this.heightOracle.charWidth; + viewFrom = findPosition(structure, (this.pixelViewport.left - marginWidth) / totalWidth); + viewTo = findPosition(structure, (this.pixelViewport.right + marginWidth) / totalWidth); } + let outside = []; + if (viewFrom > line.from) + outside.push({ from: line.from, to: viewFrom }); + if (viewTo < line.to) + outside.push({ from: viewTo, to: line.to }); + let sel = this.state.selection.main; + // Make sure the gaps don't cover a selection end + if (sel.from >= line.from && sel.from <= line.to) + cutRange(outside, sel.from - 10 /* SelectionMargin */, sel.from + 10 /* SelectionMargin */); + if (!sel.empty && sel.to >= line.from && sel.to <= line.to) + cutRange(outside, sel.to - 10 /* SelectionMargin */, sel.to + 10 /* SelectionMargin */); + for (let { from, to } of outside) + if (to - from > 1000 /* HalfMargin */) { + gaps.push(find(current, gap => gap.from >= line.from && gap.to <= line.to && + Math.abs(gap.from - from) < 1000 /* HalfMargin */ && Math.abs(gap.to - to) < 1000 /* HalfMargin */) || + new LineGap(from, to, this.gapSize(line, from, to, structure))); + } } - else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration - this.getLine().addLineDeco(deco); + return gaps; + } + gapSize(line, from, to, structure) { + let fraction = findFraction(structure, to) - findFraction(structure, from); + if (this.heightOracle.lineWrapping) { + return line.height * fraction; } - if (len) { - // Advance the iterator past the replaced content - if (this.textOff + len <= this.text.length) { - this.textOff += len; - } - else { - this.skip += len - (this.text.length - this.textOff); - this.text = ""; - this.textOff = 0; + else { + return structure.total * this.heightOracle.charWidth * fraction; + } + } + updateLineGaps(gaps) { + if (!LineGap.same(gaps, this.lineGaps)) { + this.lineGaps = gaps; + this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping))); + } + } + computeVisibleRanges() { + let deco = this.state.facet(decorations); + if (this.lineGaps.length) + deco = deco.concat(this.lineGapDeco); + let ranges = []; + rangeset.RangeSet.spans(deco, this.viewport.from, this.viewport.to, { + span(from, to) { ranges.push({ from, to }); }, + point() { } + }, 20); + let changed = ranges.length != this.visibleRanges.length || + this.visibleRanges.some((r, i) => r.from != ranges[i].from || r.to != ranges[i].to); + this.visibleRanges = ranges; + return changed ? 4 /* Viewport */ : 0; + } + lineBlockAt(pos) { + return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) || + scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler); + } + lineBlockAtHeight(height) { + return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler); + } + elementAtHeight(height) { + return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler); + } + get docHeight() { + return this.scaler.toDOM(this.heightMap.height); + } + get contentHeight() { + return this.docHeight + this.paddingTop + this.paddingBottom; + } +} +class Viewport { + constructor(from, to) { + this.from = from; + this.to = to; + } +} +function lineStructure(from, to, state) { + let ranges = [], pos = from, total = 0; + rangeset.RangeSet.spans(state.facet(decorations), from, to, { + span() { }, + point(from, to) { + if (from > pos) { + ranges.push({ from: pos, to: from }); + total += from - pos; } - this.pos = to; + pos = to; } - if (this.openStart < 0) - this.openStart = openStart; + }, 20); // We're only interested in collapsed ranges of a significant size + if (pos < to) { + ranges.push({ from: pos, to }); + total += to - pos; } - filterPoint(from, to, value, index) { - if (index < this.disallowBlockEffectsBelow && value instanceof PointDecoration) { - if (value.block) - throw new RangeError("Block decorations may not be specified via plugins"); - if (to > this.doc.lineAt(this.pos).to) - throw new RangeError("Decorations that replace line breaks may not be specified via plugins"); + return { total, ranges }; +} +function findPosition({ total, ranges }, ratio) { + if (ratio <= 0) + return ranges[0].from; + if (ratio >= 1) + return ranges[ranges.length - 1].to; + let dist = Math.floor(total * ratio); + for (let i = 0;; i++) { + let { from, to } = ranges[i], size = to - from; + if (dist <= size) + return from + dist; + dist -= size; + } +} +function findFraction(structure, pos) { + let counted = 0; + for (let { from, to } of structure.ranges) { + if (pos <= to) { + counted += pos - from; + break; } - return true; + counted += to - from; } - static build(text, from, to, decorations, pluginDecorationLength) { - let builder = new ContentBuilder(text, from, to, pluginDecorationLength); - builder.openEnd = rangeset.RangeSet.spans(decorations, from, to, builder); - if (builder.openStart < 0) - builder.openStart = builder.openEnd; - builder.finish(builder.openEnd); - return builder; + return counted / structure.total; +} +function cutRange(ranges, from, to) { + for (let i = 0; i < ranges.length; i++) { + let r = ranges[i]; + if (r.from < to && r.to > from) { + let pieces = []; + if (r.from < from) + pieces.push({ from: r.from, to: from }); + if (r.to > to) + pieces.push({ from: to, to: r.to }); + ranges.splice(i, 1, ...pieces); + i += pieces.length - 1; + } } } -function wrapMarks(view, active) { - for (let mark of active) - view = new MarkView(mark, [view], view.length); - return view; +function find(array, f) { + for (let val of array) + if (f(val)) + return val; + return undefined; } -class NullWidget extends WidgetType { - constructor(tag) { - super(); - this.tag = tag; +// Don't scale when the document height is within the range of what +// the DOM can handle. +const IdScaler = { + toDOM(n) { return n; }, + fromDOM(n) { return n; }, + scale: 1 +}; +// When the height is too big (> VP.MaxDOMHeight), scale down the +// regions outside the viewports so that the total height is +// VP.MaxDOMHeight. +class BigScaler { + constructor(doc, heightMap, viewports) { + let vpHeight = 0, base = 0, domBase = 0; + this.viewports = viewports.map(({ from, to }) => { + let top = heightMap.lineAt(from, QueryType.ByPos, doc, 0, 0).top; + let bottom = heightMap.lineAt(to, QueryType.ByPos, doc, 0, 0).bottom; + vpHeight += bottom - top; + return { from, to, top, bottom, domTop: 0, domBottom: 0 }; + }); + this.scale = (7000000 /* MaxDOMHeight */ - vpHeight) / (heightMap.height - vpHeight); + for (let obj of this.viewports) { + obj.domTop = domBase + (obj.top - base) * this.scale; + domBase = obj.domBottom = obj.domTop + (obj.bottom - obj.top); + base = obj.bottom; + } } - eq(other) { return other.tag == this.tag; } - toDOM() { return document.createElement(this.tag); } - updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; } -} - -const none = []; -const clickAddsSelectionRange = state.Facet.define(); -const dragMovesSelection$1 = state.Facet.define(); -const mouseSelectionStyle = state.Facet.define(); -const exceptionSink = state.Facet.define(); -const updateListener = state.Facet.define(); -const inputHandler = state.Facet.define(); -// FIXME remove -const scrollTo = state.StateEffect.define({ - map: (range, changes) => range.map(changes) -}); -// FIXME remove -const centerOn = state.StateEffect.define({ - map: (range, changes) => range.map(changes) -}); -class ScrollTarget { - constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) { - this.range = range; - this.y = y; - this.x = x; - this.yMargin = yMargin; - this.xMargin = xMargin; + toDOM(n) { + for (let i = 0, base = 0, domBase = 0;; i++) { + let vp = i < this.viewports.length ? this.viewports[i] : null; + if (!vp || n < vp.top) + return domBase + (n - base) * this.scale; + if (n <= vp.bottom) + return vp.domTop + (n - vp.top); + base = vp.bottom; + domBase = vp.domBottom; + } } - map(changes) { - return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin); + fromDOM(n) { + for (let i = 0, base = 0, domBase = 0;; i++) { + let vp = i < this.viewports.length ? this.viewports[i] : null; + if (!vp || n < vp.domTop) + return base + (n - domBase) / this.scale; + if (n <= vp.domBottom) + return vp.top + (n - vp.domTop); + base = vp.bottom; + domBase = vp.domBottom; + } } } -const scrollIntoView = state.StateEffect.define({ map: (t, ch) => t.map(ch) }); -/** -Log or report an unhandled exception in client code. Should -probably only be used by extension code that allows client code to -provide functions, and calls those functions in a context where an -exception can't be propagated to calling code in a reasonable way -(for example when in an event handler). - -Either calls a handler registered with -[`EditorView.exceptionSink`](https://codemirror.net/6/docs/ref/#view.EditorView^exceptionSink), -`window.onerror`, if defined, or `console.error` (in which case -it'll pass `context`, when given, as first argument). -*/ -function logException(state, exception, context) { - let handler = state.facet(exceptionSink); - if (handler.length) - handler[0](exception); - else if (window.onerror) - window.onerror(String(exception), context, undefined, undefined, exception); - else if (context) - console.error(context + ":", exception); - else - console.error(exception); +function scaleBlock(block, scaler) { + if (scaler.scale == 1) + return block; + let bTop = scaler.toDOM(block.top), bBottom = scaler.toDOM(block.bottom); + return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler)) : block.type); } -const editable = state.Facet.define({ combine: values => values.length ? values[0] : true }); -/** -Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which -[fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin) -provides. -*/ -class PluginFieldProvider { - /** - @internal - */ - constructor( - /** - @internal - */ - field, - /** - @internal - */ - get) { - this.field = field; - this.get = get; - } + +const theme = state.Facet.define({ combine: strs => strs.join(" ") }); +const darkTheme = state.Facet.define({ combine: values => values.indexOf(true) > -1 }); +const baseThemeID = styleMod.StyleModule.newName(), baseLightID = styleMod.StyleModule.newName(), baseDarkID = styleMod.StyleModule.newName(); +const lightDarkIDs = { "&light": "." + baseLightID, "&dark": "." + baseDarkID }; +function buildTheme(main, spec, scopes) { + return new styleMod.StyleModule(spec, { + finish(sel) { + return /&/.test(sel) ? sel.replace(/&\w*/, m => { + if (m == "&") + return main; + if (!scopes || !scopes[m]) + throw new RangeError(`Unsupported selector: ${m}`); + return scopes[m]; + }) : main + " " + sel; + } + }); } -/** -Plugin fields are a mechanism for allowing plugins to provide -values that can be retrieved through the -[`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method. -*/ -class PluginField { - /** - Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field, - to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) - option. - */ - from(get) { - return new PluginFieldProvider(this, get); +const baseTheme = buildTheme("." + baseThemeID, { + "&.cm-editor": { + position: "relative !important", + boxSizing: "border-box", + "&.cm-focused": { + // Provide a simple default outline to make sure a focused + // editor is visually distinct. Can't leave the default behavior + // because that will apply to the content element, which is + // inside the scrollable container and doesn't include the + // gutters. We also can't use an 'auto' outline, since those + // are, for some reason, drawn behind the element content, which + // will cause things like the active line background to cover + // the outline (#297). + outline: "1px dotted #212121" + }, + display: "flex !important", + flexDirection: "column" + }, + ".cm-scroller": { + display: "flex !important", + alignItems: "flex-start !important", + fontFamily: "monospace", + lineHeight: 1.4, + height: "100%", + overflowX: "auto", + position: "relative", + zIndex: 0 + }, + ".cm-content": { + margin: 0, + flexGrow: 2, + minHeight: "100%", + display: "block", + whiteSpace: "pre", + wordWrap: "normal", + boxSizing: "border-box", + padding: "4px 0", + outline: "none", + "&[contenteditable=true]": { + WebkitUserModify: "read-write-plaintext-only", + } + }, + ".cm-lineWrapping": { + whiteSpace_fallback: "pre-wrap", + whiteSpace: "break-spaces", + wordBreak: "break-word", + overflowWrap: "anywhere" + }, + "&light .cm-content": { caretColor: "black" }, + "&dark .cm-content": { caretColor: "white" }, + ".cm-line": { + display: "block", + padding: "0 2px 0 4px" + }, + ".cm-selectionLayer": { + zIndex: -1, + contain: "size style" + }, + ".cm-selectionBackground": { + position: "absolute", + }, + "&light .cm-selectionBackground": { + background: "#d9d9d9" + }, + "&dark .cm-selectionBackground": { + background: "#222" + }, + "&light.cm-focused .cm-selectionBackground": { + background: "#d7d4f0" + }, + "&dark.cm-focused .cm-selectionBackground": { + background: "#233" + }, + ".cm-cursorLayer": { + zIndex: 100, + contain: "size style", + pointerEvents: "none" + }, + "&.cm-focused .cm-cursorLayer": { + animation: "steps(1) cm-blink 1.2s infinite" + }, + // Two animations defined so that we can switch between them to + // restart the animation without forcing another style + // recomputation. + "@keyframes cm-blink": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} }, + "@keyframes cm-blink2": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} }, + ".cm-cursor, .cm-dropCursor": { + position: "absolute", + borderLeft: "1.2px solid black", + marginLeft: "-0.6px", + pointerEvents: "none", + }, + ".cm-cursor": { + display: "none" + }, + "&dark .cm-cursor": { + borderLeftColor: "#444" + }, + "&.cm-focused .cm-cursor": { + display: "block" + }, + "&light .cm-activeLine": { backgroundColor: "#f3f9ff" }, + "&dark .cm-activeLine": { backgroundColor: "#223039" }, + "&light .cm-specialChar": { color: "red" }, + "&dark .cm-specialChar": { color: "#f78" }, + ".cm-tab": { + display: "inline-block", + overflow: "hidden", + verticalAlign: "bottom" + }, + ".cm-placeholder": { + color: "#888", + display: "inline-block", + verticalAlign: "top", + }, + ".cm-button": { + verticalAlign: "middle", + color: "inherit", + fontSize: "70%", + padding: ".2em 1em", + borderRadius: "1px" + }, + "&light .cm-button": { + backgroundImage: "linear-gradient(#eff1f5, #d9d9df)", + border: "1px solid #888", + "&:active": { + backgroundImage: "linear-gradient(#b4b4b4, #d0d3d6)" + } + }, + "&dark .cm-button": { + backgroundImage: "linear-gradient(#393939, #111)", + border: "1px solid #888", + "&:active": { + backgroundImage: "linear-gradient(#111, #333)" + } + }, + ".cm-textfield": { + verticalAlign: "middle", + color: "inherit", + fontSize: "70%", + border: "1px solid silver", + padding: ".2em .5em" + }, + "&light .cm-textfield": { + backgroundColor: "white" + }, + "&dark .cm-textfield": { + border: "1px solid #555", + backgroundColor: "inherit" } - /** - Define a new plugin field. - */ - static define() { return new PluginField(); } -} -/** -This field can be used by plugins to provide -[decorations](https://codemirror.net/6/docs/ref/#view.Decoration). +}, lightDarkIDs); -**Note**: For reasons of data flow (plugins are only updated -after the viewport is computed), decorations produced by plugins -are _not_ taken into account when predicting the vertical layout -structure of the editor. They **must not** introduce block -widgets (that will raise an error) or replacing decorations that -cover line breaks (these will be ignored if they occur). Such -decorations, or others that cause a large amount of vertical -size shift compared to the undecorated content, should be -provided through the state-level [`decorations` -facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead. -*/ -PluginField.decorations = PluginField.define(); -/** -Used to provide ranges that should be treated as atoms as far as -cursor motion is concerned. This causes methods like -[`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and -[`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the -commands built on top of them) to skip across such regions when -a selection endpoint would enter them. This does _not_ prevent -direct programmatic [selection -updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such -regions. -*/ -PluginField.atomicRanges = PluginField.define(); -/** -Plugins can provide additional scroll margins (space around the -sides of the scrolling element that should be considered -invisible) through this field. This can be useful when the -plugin introduces elements that cover part of that element (for -example a horizontally fixed gutter). -*/ -PluginField.scrollMargins = PluginField.define(); -let nextPluginID = 0; -const viewPlugin = state.Facet.define(); -/** -View plugins associate stateful values with a view. They can -influence the way the content is drawn, and are notified of things -that happen in the view. -*/ -class ViewPlugin { - constructor( - /** - @internal - */ - id, - /** - @internal - */ - create, - /** - @internal - */ - fields) { - this.id = id; - this.create = create; - this.fields = fields; - this.extension = viewPlugin.of(this); +const observeOptions = { + childList: true, + characterData: true, + subtree: true, + attributes: true, + characterDataOldValue: true +}; +// IE11 has very broken mutation observers, so we also listen to +// DOMCharacterDataModified there +const useCharData = browser.ie && browser.ie_version <= 11; +class DOMObserver { + constructor(view, onChange, onScrollChanged) { + this.view = view; + this.onChange = onChange; + this.onScrollChanged = onScrollChanged; + this.active = false; + // The known selection. Kept in our own object, as opposed to just + // directly accessing the selection because: + // - Safari doesn't report the right selection in shadow DOM + // - Reading from the selection forces a DOM layout + // - This way, we can ignore selectionchange events if we have + // already seen the 'new' selection + this.selectionRange = new DOMSelectionState; + // Set when a selection change is detected, cleared on flush + this.selectionChanged = false; + this.delayedFlush = -1; + this.resizeTimeout = -1; + this.queue = []; + this.delayedAndroidKey = null; + this.scrollTargets = []; + this.intersection = null; + this.resize = null; + this.intersecting = false; + this.gapIntersection = null; + this.gaps = []; + // Timeout for scheduling check of the parents that need scroll handlers + this.parentCheck = -1; + this.dom = view.contentDOM; + this.observer = new MutationObserver(mutations => { + for (let mut of mutations) + this.queue.push(mut); + // IE11 will sometimes (on typing over a selection or + // backspacing out a single character text node) call the + // observer callback before actually updating the DOM. + // + // Unrelatedly, iOS Safari will, when ending a composition, + // sometimes first clear it, deliver the mutations, and then + // reinsert the finished text. CodeMirror's handling of the + // deletion will prevent the reinsertion from happening, + // breaking composition. + if ((browser.ie && browser.ie_version <= 11 || browser.ios && view.composing) && + mutations.some(m => m.type == "childList" && m.removedNodes.length || + m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length)) + this.flushSoon(); + else + this.flush(); + }); + if (useCharData) + this.onCharData = (event) => { + this.queue.push({ target: event.target, + type: "characterData", + oldValue: event.prevValue }); + this.flushSoon(); + }; + this.onSelectionChange = this.onSelectionChange.bind(this); + if (typeof ResizeObserver == "function") { + this.resize = new ResizeObserver(() => { + if (this.view.docView.lastUpdate < Date.now() - 75 && this.resizeTimeout < 0) + this.resizeTimeout = setTimeout(() => { + this.resizeTimeout = -1; + this.view.requestMeasure(); + }, 50); + }); + this.resize.observe(view.scrollDOM); + } + this.start(); + this.onScroll = this.onScroll.bind(this); + window.addEventListener("scroll", this.onScroll); + if (typeof IntersectionObserver == "function") { + this.intersection = new IntersectionObserver(entries => { + if (this.parentCheck < 0) + this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000); + if (entries.length > 0 && (entries[entries.length - 1].intersectionRatio > 0) != this.intersecting) { + this.intersecting = !this.intersecting; + if (this.intersecting != this.view.inView) + this.onScrollChanged(document.createEvent("Event")); + } + }, {}); + this.intersection.observe(this.dom); + this.gapIntersection = new IntersectionObserver(entries => { + if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0) + this.onScrollChanged(document.createEvent("Event")); + }, {}); + } + this.listenForScroll(); + this.readSelectionRange(); + this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange); } - /** - Define a plugin from a constructor function that creates the - plugin's value, given an editor view. - */ - static define(create, spec) { - let { eventHandlers, provide, decorations } = spec || {}; - let fields = []; - if (provide) - for (let provider of Array.isArray(provide) ? provide : [provide]) - fields.push(provider); - if (eventHandlers) - fields.push(domEventHandlers.from((value) => ({ plugin: value, handlers: eventHandlers }))); - if (decorations) - fields.push(PluginField.decorations.from(decorations)); - return new ViewPlugin(nextPluginID++, create, fields); + onScroll(e) { + if (this.intersecting) + this.flush(false); + this.onScrollChanged(e); } - /** - Create a plugin for a class whose constructor takes a single - editor view as argument. - */ - static fromClass(cls, spec) { - return ViewPlugin.define(view => new cls(view), spec); + updateGaps(gaps) { + if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) { + this.gapIntersection.disconnect(); + for (let gap of gaps) + this.gapIntersection.observe(gap); + this.gaps = gaps; + } } -} -const domEventHandlers = PluginField.define(); -class PluginInstance { - constructor(spec) { - this.spec = spec; - // When starting an update, all plugins have this field set to the - // update object, indicating they need to be updated. When finished - // updating, it is set to `false`. Retrieving a plugin that needs to - // be updated with `view.plugin` forces an eager update. - this.mustUpdate = null; - // This is null when the plugin is initially created, but - // initialized on the first update. - this.value = null; + onSelectionChange(event) { + if (!this.readSelectionRange() || this.delayedAndroidKey) + return; + let { view } = this, sel = this.selectionRange; + if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(view.dom, sel)) + return; + let context = sel.anchorNode && view.docView.nearest(sel.anchorNode); + if (context && context.ignoreEvent(event)) + return; + // Deletions on IE11 fire their events in the wrong order, giving + // us a selection change event before the DOM changes are + // reported. + // Chrome Android has a similar issue when backspacing out a + // selection (#645). + if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty && + // (Selection.isCollapsed isn't reliable on IE) + sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset)) + this.flushSoon(); + else + this.flush(false); } - takeField(type, target) { - if (this.spec) - for (let { field, get } of this.spec.fields) - if (field == type) - target.push(get(this.value)); + readSelectionRange() { + let { root } = this.view, domSel = getSelection(root); + // The Selection object is broken in shadow roots in Safari. See + // https://github.com/codemirror/codemirror.next/issues/414 + let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.view.contentDOM && + safariSelectionRangeHack(this.view) || domSel; + if (this.selectionRange.eq(range)) + return false; + this.selectionRange.setRange(range); + return this.selectionChanged = true; } - update(view) { - if (!this.value) { - if (this.spec) { - try { - this.value = this.spec.create(view); - } - catch (e) { - logException(view.state, e, "CodeMirror plugin crashed"); - this.deactivate(); - } + setSelectionRange(anchor, head) { + this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset); + this.selectionChanged = false; + } + listenForScroll() { + this.parentCheck = -1; + let i = 0, changed = null; + for (let dom = this.dom; dom;) { + if (dom.nodeType == 1) { + if (!changed && i < this.scrollTargets.length && this.scrollTargets[i] == dom) + i++; + else if (!changed) + changed = this.scrollTargets.slice(0, i); + if (changed) + changed.push(dom); + dom = dom.assignedSlot || dom.parentNode; } - } - else if (this.mustUpdate) { - let update = this.mustUpdate; - this.mustUpdate = null; - if (this.value.update) { - try { - this.value.update(update); - } - catch (e) { - logException(update.state, e, "CodeMirror plugin crashed"); - if (this.value.destroy) - try { - this.value.destroy(); - } - catch (_) { } - this.deactivate(); - } + else if (dom.nodeType == 11) { // Shadow root + dom = dom.host; + } + else { + break; } } - return this; + if (i < this.scrollTargets.length && !changed) + changed = this.scrollTargets.slice(0, i); + if (changed) { + for (let dom of this.scrollTargets) + dom.removeEventListener("scroll", this.onScroll); + for (let dom of this.scrollTargets = changed) + dom.addEventListener("scroll", this.onScroll); + } } - destroy(view) { - var _a; - if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.destroy) { - try { - this.value.destroy(); - } - catch (e) { - logException(view.state, e, "CodeMirror plugin crashed"); - } + ignore(f) { + if (!this.active) + return f(); + try { + this.stop(); + return f(); + } + finally { + this.start(); + this.clear(); } } - deactivate() { - this.spec = this.value = null; + start() { + if (this.active) + return; + this.observer.observe(this.dom, observeOptions); + if (useCharData) + this.dom.addEventListener("DOMCharacterDataModified", this.onCharData); + this.active = true; } -} -const editorAttributes = state.Facet.define(); -const contentAttributes = state.Facet.define(); -// Provide decorations -const decorations = state.Facet.define(); -const styleModule = state.Facet.define(); -class ChangedRange { - constructor(fromA, toA, fromB, toB) { - this.fromA = fromA; - this.toA = toA; - this.fromB = fromB; - this.toB = toB; + stop() { + if (!this.active) + return; + this.active = false; + this.observer.disconnect(); + if (useCharData) + this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData); } - join(other) { - return new ChangedRange(Math.min(this.fromA, other.fromA), Math.max(this.toA, other.toA), Math.min(this.fromB, other.fromB), Math.max(this.toB, other.toB)); + // Throw away any pending changes + clear() { + this.observer.takeRecords(); + this.queue.length = 0; + this.selectionChanged = false; } - addToSet(set) { - let i = set.length, me = this; - for (; i > 0; i--) { - let range = set[i - 1]; - if (range.fromA > me.toA) - continue; - if (range.toA < me.fromA) - break; - me = me.join(range); - set.splice(i - 1, 1); + // Chrome Android, especially in combination with GBoard, not only + // doesn't reliably fire regular key events, but also often + // surrounds the effect of enter or backspace with a bunch of + // composition events that, when interrupted, cause text duplication + // or other kinds of corruption. This hack makes the editor back off + // from handling DOM changes for a moment when such a key is + // detected (via beforeinput or keydown), and then dispatches the + // key event, throwing away the DOM changes if it gets handled. + delayAndroidKey(key, keyCode) { + if (!this.delayedAndroidKey) + requestAnimationFrame(() => { + let key = this.delayedAndroidKey; + this.delayedAndroidKey = null; + let startState = this.view.state; + if (dispatchKey(this.view.contentDOM, key.key, key.keyCode)) + this.processRecords(); + else + this.flush(); + if (this.view.state == startState) + this.view.update([]); + }); + // Since backspace beforeinput is sometimes signalled spuriously, + // Enter always takes precedence. + if (!this.delayedAndroidKey || key == "Enter") + this.delayedAndroidKey = { key, keyCode }; + } + flushSoon() { + if (this.delayedFlush < 0) + this.delayedFlush = window.setTimeout(() => { this.delayedFlush = -1; this.flush(); }, 20); + } + forceFlush() { + if (this.delayedFlush >= 0) { + window.clearTimeout(this.delayedFlush); + this.delayedFlush = -1; + this.flush(); } - set.splice(i, 0, me); - return set; } - static extendWithRanges(diff, ranges) { - if (ranges.length == 0) - return diff; - let result = []; - for (let dI = 0, rI = 0, posA = 0, posB = 0;; dI++) { - let next = dI == diff.length ? null : diff[dI], off = posA - posB; - let end = next ? next.fromB : 1e9; - while (rI < ranges.length && ranges[rI] < end) { - let from = ranges[rI], to = ranges[rI + 1]; - let fromB = Math.max(posB, from), toB = Math.min(end, to); - if (fromB <= toB) - new ChangedRange(fromB + off, toB + off, fromB, toB).addToSet(result); - if (to > end) - break; - else - rI += 2; + processRecords() { + let records = this.queue; + for (let mut of this.observer.takeRecords()) + records.push(mut); + if (records.length) + this.queue = []; + let from = -1, to = -1, typeOver = false; + for (let record of records) { + let range = this.readMutation(record); + if (!range) + continue; + if (range.typeOver) + typeOver = true; + if (from == -1) { + ({ from, to } = range); } - if (!next) - return result; - new ChangedRange(next.fromA, next.toA, next.fromB, next.toB).addToSet(result); - posA = next.toA; - posB = next.toB; + else { + from = Math.min(range.from, from); + to = Math.max(range.to, to); + } + } + return { from, to, typeOver }; + } + // Apply pending changes, if any + flush(readSelection = true) { + // Completely hold off flushing when pending keys are set—the code + // managing those will make sure processRecords is called and the + // view is resynchronized after + if (this.delayedFlush >= 0 || this.delayedAndroidKey) + return; + if (readSelection) + this.readSelectionRange(); + let { from, to, typeOver } = this.processRecords(); + let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange); + if (from < 0 && !newSel) + return; + this.selectionChanged = false; + let startState = this.view.state; + this.onChange(from, to, typeOver); + // The view wasn't updated + if (this.view.state == startState) + this.view.update([]); + } + readMutation(rec) { + let cView = this.view.docView.nearest(rec.target); + if (!cView || cView.ignoreMutation(rec)) + return null; + cView.markDirty(rec.type == "attributes"); + if (rec.type == "attributes") + cView.dirty |= 4 /* Attrs */; + if (rec.type == "childList") { + let childBefore = findChild(cView, rec.previousSibling || rec.target.previousSibling, -1); + let childAfter = findChild(cView, rec.nextSibling || rec.target.nextSibling, 1); + return { from: childBefore ? cView.posAfter(childBefore) : cView.posAtStart, + to: childAfter ? cView.posBefore(childAfter) : cView.posAtEnd, typeOver: false }; + } + else if (rec.type == "characterData") { + return { from: cView.posAtStart, to: cView.posAtEnd, typeOver: rec.target.nodeValue == rec.oldValue }; } + else { + return null; + } + } + destroy() { + var _a, _b, _c; + this.stop(); + (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect(); + (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect(); + (_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect(); + for (let dom of this.scrollTargets) + dom.removeEventListener("scroll", this.onScroll); + window.removeEventListener("scroll", this.onScroll); + this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange); + clearTimeout(this.parentCheck); + clearTimeout(this.resizeTimeout); } } -/** -View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this -class, which describe what happened, whenever the view is updated. -*/ -class ViewUpdate { - /** - @internal - */ - constructor( - /** - The editor view that the update is associated with. - */ - view, - /** - The new editor state. - */ - state$1, - /** - The transactions involved in the update. May be empty. - */ - transactions = none) { - this.view = view; - this.state = state$1; - this.transactions = transactions; - /** - @internal - */ - this.flags = 0; - this.startState = view.state; - this.changes = state.ChangeSet.empty(this.startState.doc.length); - for (let tr of transactions) - this.changes = this.changes.compose(tr.changes); - let changedRanges = []; - this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB))); - this.changedRanges = changedRanges; - let focus = view.hasFocus; - if (focus != view.inputState.notifiedFocused) { - view.inputState.notifiedFocused = focus; - this.flags |= 1 /* Focus */; +function findChild(cView, dom, dir) { + while (dom) { + let curView = ContentView.get(dom); + if (curView && curView.parent == cView) + return curView; + let parent = dom.parentNode; + dom = parent != cView.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling; + } + return null; +} +// Used to work around a Safari Selection/shadow DOM bug (#414) +function safariSelectionRangeHack(view) { + let found = null; + // Because Safari (at least in 2018-2021) doesn't provide regular + // access to the selection inside a shadowroot, we have to perform a + // ridiculous hack to get at it—using `execCommand` to trigger a + // `beforeInput` event so that we can read the target range from the + // event. + function read(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + found = event.getTargetRanges()[0]; + } + view.contentDOM.addEventListener("beforeinput", read, true); + document.execCommand("indent"); + view.contentDOM.removeEventListener("beforeinput", read, true); + if (!found) + return null; + let anchorNode = found.startContainer, anchorOffset = found.startOffset; + let focusNode = found.endContainer, focusOffset = found.endOffset; + let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor); + // Since such a range doesn't distinguish between anchor and head, + // use a heuristic that flips it around if its end matches the + // current anchor. + if (isEquivalentPosition(curAnchor.node, curAnchor.offset, focusNode, focusOffset)) + [anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset]; + return { anchorNode, anchorOffset, focusNode, focusOffset }; +} + +function applyDOMChange(view, start, end, typeOver) { + let change, newSel; + let sel = view.state.selection.main; + if (start > -1) { + let bounds = view.docView.domBoundsAround(start, end, 0); + if (!bounds || view.state.readOnly) + return; + let { from, to } = bounds; + let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view); + let reader = new DOMReader(selPoints, view); + reader.readRange(bounds.startDOM, bounds.endDOM); + newSel = selectionFromPoints(selPoints, from); + let preferredPos = sel.from, preferredSide = null; + // Prefer anchoring to end when Backspace is pressed (or, on + // Android, when something was deleted) + if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 || + browser.android && reader.text.length < to - from) { + preferredPos = sel.to; + preferredSide = "end"; + } + let diff = findDiff(view.state.sliceDoc(from, to), reader.text, preferredPos - from, preferredSide); + if (diff) + change = { from: from + diff.from, to: from + diff.toA, + insert: view.state.toText(reader.text.slice(diff.from, diff.toB)) }; + } + else if (view.hasFocus || !view.state.facet(editable)) { + let domSel = view.observer.selectionRange; + let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView; + let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset || + !contains(view.contentDOM, domSel.focusNode) + ? view.state.selection.main.head + : view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset); + let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset || + !contains(view.contentDOM, domSel.anchorNode) + ? view.state.selection.main.anchor + : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset); + if (head != sel.head || anchor != sel.anchor) + newSel = state.EditorSelection.single(anchor, head); + } + if (!change && !newSel) + return; + // Heuristic to notice typing over a selected character + if (!change && typeOver && !sel.empty && newSel && newSel.main.empty) + change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) }; + // If the change is inside the selection and covers most of it, + // assume it is a selection replace (with identical characters at + // the start/end not included in the diff) + else if (change && change.from >= sel.from && change.to <= sel.to && + (change.from != sel.from || change.to != sel.to) && + (sel.to - sel.from) - (change.to - change.from) <= 4) + change = { + from: sel.from, to: sel.to, + insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to)) + }; + if (change) { + let startState = view.state; + if (browser.ios && view.inputState.flushIOSKey(view)) + return; + // Android browsers don't fire reasonable key events for enter, + // backspace, or delete. So this detects changes that look like + // they're caused by those keys, and reinterprets them as key + // events. (Some of these keys are also handled by beforeinput + // events and the pendingAndroidKey mechanism, but that's not + // reliable in all situations.) + if (browser.android && + ((change.from == sel.from && change.to == sel.to && + change.insert.length == 1 && change.insert.lines == 2 && + dispatchKey(view.contentDOM, "Enter", 13)) || + (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 && + dispatchKey(view.contentDOM, "Backspace", 8)) || + (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 && + dispatchKey(view.contentDOM, "Delete", 46)))) + return; + let text = change.insert.toString(); + if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text))) + return; + if (view.inputState.composing >= 0) + view.inputState.composing++; + let tr; + if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 && + (!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length)) { + let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : ""; + let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : ""; + tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + + after)); } + else { + let changes = startState.changes(change); + tr = { + changes, + selection: newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength + ? startState.selection.replaceRange(newSel.main) : undefined + }; + } + let userEvent = "input.type"; + if (view.composing) { + userEvent += ".compose"; + if (view.inputState.compositionFirstChange) { + userEvent += ".start"; + view.inputState.compositionFirstChange = false; + } + } + view.dispatch(tr, { scrollIntoView: true, userEvent }); } - /** - Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or - [visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this - update. - */ - get viewportChanged() { - return (this.flags & 4 /* Viewport */) > 0; - } - /** - Indicates whether the height of an element in the editor changed - in this update. - */ - get heightChanged() { - return (this.flags & 2 /* Height */) > 0; + else if (newSel && !newSel.main.eq(sel)) { + let scrollIntoView = false, userEvent = "select"; + if (view.inputState.lastSelectionTime > Date.now() - 50) { + if (view.inputState.lastSelectionOrigin == "select") + scrollIntoView = true; + userEvent = view.inputState.lastSelectionOrigin; + } + view.dispatch({ selection: newSel, scrollIntoView, userEvent }); } - /** - Returns true when the document was modified or the size of the - editor, or elements within the editor, changed. - */ - get geometryChanged() { - return this.docChanged || (this.flags & (8 /* Geometry */ | 2 /* Height */)) > 0; +} +function findDiff(a, b, preferredPos, preferredSide) { + let minLen = Math.min(a.length, b.length); + let from = 0; + while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from)) + from++; + if (from == minLen && a.length == b.length) + return null; + let toA = a.length, toB = b.length; + while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) { + toA--; + toB--; } - /** - True when this update indicates a focus change. - */ - get focusChanged() { - return (this.flags & 1 /* Focus */) > 0; + if (preferredSide == "end") { + let adjust = Math.max(0, from - Math.min(toA, toB)); + preferredPos -= toA + adjust - from; } - /** - Whether the document changed in this update. - */ - get docChanged() { - return !this.changes.empty; + if (toA < from && a.length < b.length) { + let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0; + from -= move; + toB = from + (toB - toA); + toA = from; } - /** - Whether the selection was explicitly set in this update. - */ - get selectionSet() { - return this.transactions.some(tr => tr.selection); + else if (toB < from) { + let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0; + from -= move; + toA = from + (toA - toB); + toB = from; } - /** - @internal - */ - get empty() { return this.flags == 0 && this.transactions.length == 0; } + return { from, toA, toB }; } - -/** -Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). -*/ -exports.Direction = void 0; -(function (Direction) { - // (These are chosen to match the base levels, in bidi algorithm - // terms, of spans in that direction.) - /** - Left-to-right. - */ - Direction[Direction["LTR"] = 0] = "LTR"; - /** - Right-to-left. - */ - Direction[Direction["RTL"] = 1] = "RTL"; -})(exports.Direction || (exports.Direction = {})); -const LTR = exports.Direction.LTR, RTL = exports.Direction.RTL; -// Decode a string with each type encoded as log2(type) -function dec(str) { +function selectionPoints(view) { let result = []; - for (let i = 0; i < str.length; i++) - result.push(1 << +str[i]); + if (view.root.activeElement != view.contentDOM) + return result; + let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange; + if (anchorNode) { + result.push(new DOMPoint(anchorNode, anchorOffset)); + if (focusNode != anchorNode || focusOffset != anchorOffset) + result.push(new DOMPoint(focusNode, focusOffset)); + } return result; } -// Character types for codepoints 0 to 0xf8 -const LowTypes = dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008"); -// Character types for codepoints 0x600 to 0x6f9 -const ArabicTypes = dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333"); -const Brackets = Object.create(null), BracketStack = []; -// There's a lot more in -// https://www.unicode.org/Public/UCD/latest/ucd/BidiBrackets.txt, -// which are left out to keep code size down. -for (let p of ["()", "[]", "{}"]) { - let l = p.charCodeAt(0), r = p.charCodeAt(1); - Brackets[l] = r; - Brackets[r] = -l; -} -function charType(ch) { - return ch <= 0xf7 ? LowTypes[ch] : - 0x590 <= ch && ch <= 0x5f4 ? 2 /* R */ : - 0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] : - 0x6ee <= ch && ch <= 0x8ac ? 4 /* AL */ : - 0x2000 <= ch && ch <= 0x200b ? 256 /* NI */ : - ch == 0x200c ? 256 /* NI */ : 1 /* L */; +function selectionFromPoints(points, base) { + if (points.length == 0) + return null; + let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor; + return anchor > -1 && head > -1 ? state.EditorSelection.single(anchor + base, head + base) : null; } -const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + +// The editor's update state machine looks something like this: +// +// Idle → Updating ⇆ Idle (unchecked) → Measuring → Idle +// ↑ ↓ +// Updating (measure) +// +// The difference between 'Idle' and 'Idle (unchecked)' lies in +// whether a layout check has been scheduled. A regular update through +// the `update` method updates the DOM in a write-only fashion, and +// relies on a check (scheduled with `requestAnimationFrame`) to make +// sure everything is where it should be and the viewport covers the +// visible code. That check continues to measure and then optionally +// update until it reaches a coherent state. /** -Represents a contiguous range of text that has a single direction -(as in left-to-right or right-to-left). +An editor view represents the editor's user interface. It holds +the editable DOM surface, and possibly other elements such as the +line number gutter. It handles events and dispatches state +transactions for editing actions. */ -class BidiSpan { +class EditorView { /** - @internal + Construct a new view. You'll usually want to put `view.dom` into + your document after creating a view, so that the user can see + it. */ constructor( /** - The start of the span (relative to the start of the line). + Initialization options. */ - from, + config = {}) { + this.plugins = []; + this.pluginMap = new Map; + this.editorAttrs = {}; + this.contentAttrs = {}; + this.bidiCache = []; + this.destroyed = false; + /** + @internal + */ + this.updateState = 2 /* Updating */; + /** + @internal + */ + this.measureScheduled = -1; + /** + @internal + */ + this.measureRequests = []; + this.contentDOM = document.createElement("div"); + this.scrollDOM = document.createElement("div"); + this.scrollDOM.tabIndex = -1; + this.scrollDOM.className = "cm-scroller"; + this.scrollDOM.appendChild(this.contentDOM); + this.announceDOM = document.createElement("div"); + this.announceDOM.style.cssText = "position: absolute; top: -10000px"; + this.announceDOM.setAttribute("aria-live", "polite"); + this.dom = document.createElement("div"); + this.dom.appendChild(this.announceDOM); + this.dom.appendChild(this.scrollDOM); + this._dispatch = config.dispatch || ((tr) => this.update([tr])); + this.dispatch = this.dispatch.bind(this); + this.root = (config.root || getRoot(config.parent) || document); + this.viewState = new ViewState(config.state || state.EditorState.create()); + this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec)); + for (let plugin of this.plugins) + plugin.update(this); + this.observer = new DOMObserver(this, (from, to, typeOver) => { + applyDOMChange(this, from, to, typeOver); + }, event => { + this.inputState.runScrollHandlers(this, event); + if (this.observer.intersecting) + this.measure(); + }); + this.inputState = new InputState(this); + this.docView = new DocView(this); + this.mountStyles(); + this.updateAttrs(); + this.updateState = 0 /* Idle */; + ensureGlobalHandler(); + this.requestMeasure(); + if (config.parent) + config.parent.appendChild(this.dom); + } /** - The end of the span. + The current editor state. */ - to, + get state() { return this.viewState.state; } /** - The ["bidi - level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm) - of the span (in this context, 0 means - left-to-right, 1 means right-to-left, 2 means left-to-right - number inside right-to-left text). + To be able to display large documents without consuming too much + memory or overloading the browser, CodeMirror only draws the + code that is visible (plus a margin around it) to the DOM. This + property tells you the extent of the current drawn viewport, in + document positions. */ - level) { - this.from = from; - this.to = to; - this.level = level; - } + get viewport() { return this.viewState.viewport; } /** - The direction of this span. + When there are, for example, large collapsed ranges in the + viewport, its size can be a lot bigger than the actual visible + content. Thus, if you are doing something like styling the + content in the viewport, it is preferable to only do so for + these ranges, which are the subset of the viewport that is + actually drawn. */ - get dir() { return this.level % 2 ? RTL : LTR; } + get visibleRanges() { return this.viewState.visibleRanges; } /** - @internal + Returns false when the editor is entirely scrolled out of view + or otherwise hidden. */ - side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; } + get inView() { return this.viewState.inView; } /** - @internal + Indicates whether the user is currently composing text via + [IME](https://en.wikipedia.org/wiki/Input_method). */ - static find(order, index, level, assoc) { - let maybe = -1; - for (let i = 0; i < order.length; i++) { - let span = order[i]; - if (span.from <= index && span.to >= index) { - if (span.level == level) - return i; - // When multiple spans match, if assoc != 0, take the one that - // covers that side, otherwise take the one with the minimum - // level. - if (maybe < 0 || (assoc != 0 ? (assoc < 0 ? span.from < index : span.to > index) : order[maybe].level > span.level)) - maybe = i; + get composing() { return this.inputState.composing > 0; } + dispatch(...input) { + this._dispatch(input.length == 1 && input[0] instanceof state.Transaction ? input[0] + : this.state.update(...input)); + } + /** + Update the view for the given array of transactions. This will + update the visible document and selection to match the state + produced by the transactions, and notify view plugins of the + change. You should usually call + [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead, which uses this + as a primitive. + */ + update(transactions) { + if (this.updateState != 0 /* Idle */) + throw new Error("Calls to EditorView.update are not allowed while an update is in progress"); + let redrawn = false, update; + let state$1 = this.state; + for (let tr of transactions) { + if (tr.startState != state$1) + throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state."); + state$1 = tr.state; + } + if (this.destroyed) { + this.viewState.state = state$1; + return; + } + // When the phrases change, redraw the editor + if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases)) + return this.setState(state$1); + update = new ViewUpdate(this, state$1, transactions); + let scrollTarget = this.viewState.scrollTarget; + try { + this.updateState = 2 /* Updating */; + for (let tr of transactions) { + if (scrollTarget) + scrollTarget = scrollTarget.map(tr.changes); + if (tr.scrollIntoView) { + let { main } = tr.state.selection; + scrollTarget = new ScrollTarget(main.empty ? main : state.EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1)); + } + for (let e of tr.effects) { + if (e.is(scrollTo)) + scrollTarget = new ScrollTarget(e.value); + else if (e.is(centerOn)) + scrollTarget = new ScrollTarget(e.value, "center"); + else if (e.is(scrollIntoView)) + scrollTarget = e.value; + } } + this.viewState.update(update, scrollTarget); + this.bidiCache = CachedOrder.update(this.bidiCache, update.changes); + if (!update.empty) { + this.updatePlugins(update); + this.inputState.update(update); + } + redrawn = this.docView.update(update); + if (this.state.facet(styleModule) != this.styleModules) + this.mountStyles(); + this.updateAttrs(); + this.showAnnouncements(transactions); + this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer"))); } - if (maybe < 0) - throw new RangeError("Index out of range"); - return maybe; - } -} -// Reused array of character types -const types = []; -function computeOrder(line, direction) { - let len = line.length, outerType = direction == LTR ? 1 /* L */ : 2 /* R */, oppositeType = direction == LTR ? 2 /* R */ : 1 /* L */; - if (!line || outerType == 1 /* L */ && !BidiRE.test(line)) - return trivialOrder(len); - // W1. Examine each non-spacing mark (NSM) in the level run, and - // change the type of the NSM to the type of the previous - // character. If the NSM is at the start of the level run, it will - // get the type of sor. - // W2. Search backwards from each instance of a European number - // until the first strong type (R, L, AL, or sor) is found. If an - // AL is found, change the type of the European number to Arabic - // number. - // W3. Change all ALs to R. - // (Left after this: L, R, EN, AN, ET, CS, NI) - for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) { - let type = charType(line.charCodeAt(i)); - if (type == 512 /* NSM */) - type = prev; - else if (type == 8 /* EN */ && prevStrong == 4 /* AL */) - type = 16 /* AN */; - types[i] = type == 4 /* AL */ ? 2 /* R */ : type; - if (type & 7 /* Strong */) - prevStrong = type; - prev = type; + finally { + this.updateState = 0 /* Idle */; + } + if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc) + this.requestMeasure(); + if (!update.empty) + for (let listener of this.state.facet(updateListener)) + listener(update); } - // W5. A sequence of European terminators adjacent to European - // numbers changes to all European numbers. - // W6. Otherwise, separators and terminators change to Other - // Neutral. - // W7. Search backwards from each instance of a European number - // until the first strong type (R, L, or sor) is found. If an L is - // found, then change the type of the European number to L. - // (Left after this: L, R, EN+AN, NI) - for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) { - let type = types[i]; - if (type == 128 /* CS */) { - if (i < len - 1 && prev == types[i + 1] && (prev & 24 /* Num */)) - type = types[i] = prev; - else - types[i] = 256 /* NI */; + /** + Reset the view to the given state. (This will cause the entire + document to be redrawn and all view plugins to be reinitialized, + so you should probably only use it when the new state isn't + derived from the old state. Otherwise, use + [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead.) + */ + setState(newState) { + if (this.updateState != 0 /* Idle */) + throw new Error("Calls to EditorView.setState are not allowed while an update is in progress"); + if (this.destroyed) { + this.viewState.state = newState; + return; } - else if (type == 64 /* ET */) { - let end = i + 1; - while (end < len && types[end] == 64 /* ET */) - end++; - let replace = (i && prev == 8 /* EN */) || (end < len && types[end] == 8 /* EN */) ? (prevStrong == 1 /* L */ ? 1 /* L */ : 8 /* EN */) : 256 /* NI */; - for (let j = i; j < end; j++) - types[j] = replace; - i = end - 1; + this.updateState = 2 /* Updating */; + try { + for (let plugin of this.plugins) + plugin.destroy(this); + this.viewState = new ViewState(newState); + this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec)); + this.pluginMap.clear(); + for (let plugin of this.plugins) + plugin.update(this); + this.docView = new DocView(this); + this.inputState.ensureHandlers(this); + this.mountStyles(); + this.updateAttrs(); + this.bidiCache = []; } - else if (type == 8 /* EN */ && prevStrong == 1 /* L */) { - types[i] = 1 /* L */; + finally { + this.updateState = 0 /* Idle */; } - prev = type; - if (type & 7 /* Strong */) - prevStrong = type; + this.requestMeasure(); } - // N0. Process bracket pairs in an isolating run sequence - // sequentially in the logical order of the text positions of the - // opening paired brackets using the logic given below. Within this - // scope, bidirectional types EN and AN are treated as R. - for (let i = 0, sI = 0, context = 0, ch, br, type; i < len; i++) { - // Keeps [startIndex, type, strongSeen] triples for each open - // bracket on BracketStack. - if (br = Brackets[ch = line.charCodeAt(i)]) { - if (br < 0) { // Closing bracket - for (let sJ = sI - 3; sJ >= 0; sJ -= 3) { - if (BracketStack[sJ + 1] == -br) { - let flags = BracketStack[sJ + 2]; - let type = (flags & 2 /* EmbedInside */) ? outerType : - !(flags & 4 /* OppositeInside */) ? 0 : - (flags & 1 /* OppositeBefore */) ? oppositeType : outerType; - if (type) - types[i] = types[BracketStack[sJ]] = type; - sI = sJ; - break; - } + updatePlugins(update) { + let prevSpecs = update.startState.facet(viewPlugin), specs = update.state.facet(viewPlugin); + if (prevSpecs != specs) { + let newPlugins = []; + for (let spec of specs) { + let found = prevSpecs.indexOf(spec); + if (found < 0) { + newPlugins.push(new PluginInstance(spec)); + } + else { + let plugin = this.plugins[found]; + plugin.mustUpdate = update; + newPlugins.push(plugin); } } - else if (BracketStack.length == 189 /* MaxDepth */) { - break; - } - else { - BracketStack[sI++] = i; - BracketStack[sI++] = ch; - BracketStack[sI++] = context; - } + for (let plugin of this.plugins) + if (plugin.mustUpdate != update) + plugin.destroy(this); + this.plugins = newPlugins; + this.pluginMap.clear(); + this.inputState.ensureHandlers(this); } - else if ((type = types[i]) == 2 /* R */ || type == 1 /* L */) { - let embed = type == outerType; - context = embed ? 0 : 1 /* OppositeBefore */; - for (let sJ = sI - 3; sJ >= 0; sJ -= 3) { - let cur = BracketStack[sJ + 2]; - if (cur & 2 /* EmbedInside */) + else { + for (let p of this.plugins) + p.mustUpdate = update; + } + for (let i = 0; i < this.plugins.length; i++) + this.plugins[i].update(this); + } + /** + @internal + */ + measure(flush = true) { + if (this.destroyed) + return; + if (this.measureScheduled > -1) + cancelAnimationFrame(this.measureScheduled); + this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame + if (flush) + this.observer.flush(); + let updated = null; + try { + for (let i = 0;; i++) { + this.updateState = 1 /* Measuring */; + let oldViewport = this.viewport; + let changed = this.viewState.measure(this); + if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null) + break; + if (i > 5) { + console.warn(this.measureRequests.length + ? "Measure loop restarted more than 5 times" + : "Viewport failed to stabilize"); break; - if (embed) { - BracketStack[sJ + 2] |= 2 /* EmbedInside */; } - else { - if (cur & 4 /* OppositeInside */) - break; - BracketStack[sJ + 2] |= 4 /* OppositeInside */; + let measuring = []; + // Only run measure requests in this cycle when the viewport didn't change + if (!(changed & 4 /* Viewport */)) + [this.measureRequests, measuring] = [measuring, this.measureRequests]; + let measured = measuring.map(m => { + try { + return m.read(this); + } + catch (e) { + logException(this.state, e); + return BadMeasure; + } + }); + let update = new ViewUpdate(this, this.state), redrawn = false; + update.flags |= changed; + if (!updated) + updated = update; + else + updated.flags |= changed; + this.updateState = 2 /* Updating */; + if (!update.empty) { + this.updatePlugins(update); + this.inputState.update(update); + this.updateAttrs(); + redrawn = this.docView.update(update); + } + for (let i = 0; i < measuring.length; i++) + if (measured[i] != BadMeasure) { + try { + let m = measuring[i]; + if (m.write) + m.write(measured[i], this); + } + catch (e) { + logException(this.state, e); + } + } + if (this.viewState.scrollTarget) { + this.docView.scrollIntoView(this.viewState.scrollTarget); + this.viewState.scrollTarget = null; } + if (redrawn) + this.docView.updateSelection(true); + if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && + this.measureRequests.length == 0) + break; } } - } - // N1. A sequence of neutrals takes the direction of the - // surrounding strong text if the text on both sides has the same - // direction. European and Arabic numbers act as if they were R in - // terms of their influence on neutrals. Start-of-level-run (sor) - // and end-of-level-run (eor) are used at level run boundaries. - // N2. Any remaining neutrals take the embedding direction. - // (Left after this: L, R, EN+AN) - for (let i = 0; i < len; i++) { - if (types[i] == 256 /* NI */) { - let end = i + 1; - while (end < len && types[end] == 256 /* NI */) - end++; - let beforeL = (i ? types[i - 1] : outerType) == 1 /* L */; - let afterL = (end < len ? types[end] : outerType) == 1 /* L */; - let replace = beforeL == afterL ? (beforeL ? 1 /* L */ : 2 /* R */) : outerType; - for (let j = i; j < end; j++) - types[j] = replace; - i = end - 1; + finally { + this.updateState = 0 /* Idle */; + this.measureScheduled = -1; } + if (updated && !updated.empty) + for (let listener of this.state.facet(updateListener)) + listener(updated); } - // Here we depart from the documented algorithm, in order to avoid - // building up an actual levels array. Since there are only three - // levels (0, 1, 2) in an implementation that doesn't take - // explicit embedding into account, we can build up the order on - // the fly, without following the level-based algorithm. - let order = []; - if (outerType == 1 /* L */) { - for (let i = 0; i < len;) { - let start = i, rtl = types[i++] != 1 /* L */; - while (i < len && rtl == (types[i] != 1 /* L */)) - i++; - if (rtl) { - for (let j = i; j > start;) { - let end = j, l = types[--j] != 2 /* R */; - while (j > start && l == (types[j - 1] != 2 /* R */)) - j--; - order.push(new BidiSpan(j, end, l ? 2 : 1)); - } - } - else { - order.push(new BidiSpan(start, i, 0)); - } - } + /** + Get the CSS classes for the currently active editor themes. + */ + get themeClasses() { + return baseThemeID + " " + + (this.state.facet(darkTheme) ? baseDarkID : baseLightID) + " " + + this.state.facet(theme); } - else { - for (let i = 0; i < len;) { - let start = i, rtl = types[i++] == 2 /* R */; - while (i < len && rtl == (types[i] == 2 /* R */)) - i++; - order.push(new BidiSpan(start, i, rtl ? 1 : 2)); - } + updateAttrs() { + let editorAttrs = attrsFromFacet(this, editorAttributes, { + class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses + }); + let contentAttrs = { + spellcheck: "false", + autocorrect: "off", + autocapitalize: "off", + translate: "no", + contenteditable: !this.state.facet(editable) ? "false" : "true", + class: "cm-content", + style: `${browser.tabSize}: ${this.state.tabSize}`, + role: "textbox", + "aria-multiline": "true" + }; + if (this.state.readOnly) + contentAttrs["aria-readonly"] = "true"; + attrsFromFacet(this, contentAttributes, contentAttrs); + this.observer.ignore(() => { + updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs); + updateAttrs(this.dom, this.editorAttrs, editorAttrs); + }); + this.editorAttrs = editorAttrs; + this.contentAttrs = contentAttrs; } - return order; -} -function trivialOrder(length) { - return [new BidiSpan(0, length, 0)]; -} -let movedOver = ""; -function moveVisually(line, order, dir, start, forward) { - var _a; - let startIndex = start.head - line.from, spanI = -1; - if (startIndex == 0) { - if (!forward || !line.length) - return null; - if (order[0].level != dir) { - startIndex = order[0].side(false, dir); - spanI = 0; - } + showAnnouncements(trs) { + let first = true; + for (let tr of trs) + for (let effect of tr.effects) + if (effect.is(EditorView.announce)) { + if (first) + this.announceDOM.textContent = ""; + first = false; + let div = this.announceDOM.appendChild(document.createElement("div")); + div.textContent = effect.value; + } } - else if (startIndex == line.length) { - if (forward) - return null; - let last = order[order.length - 1]; - if (last.level != dir) { - startIndex = last.side(true, dir); - spanI = order.length - 1; - } + mountStyles() { + this.styleModules = this.state.facet(styleModule); + styleMod.StyleModule.mount(this.root, this.styleModules.concat(baseTheme).reverse()); } - if (spanI < 0) - spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc); - let span = order[spanI]; - // End of span. (But not end of line--that was checked for above.) - if (startIndex == span.side(forward, dir)) { - span = order[spanI += forward ? 1 : -1]; - startIndex = span.side(!forward, dir); + readMeasured() { + if (this.updateState == 2 /* Updating */) + throw new Error("Reading the editor layout isn't allowed during an update"); + if (this.updateState == 0 /* Idle */ && this.measureScheduled > -1) + this.measure(false); } - let indexForward = forward == (span.dir == dir); - let nextIndex = text.findClusterBreak(line.text, startIndex, indexForward); - movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex)); - if (nextIndex != span.side(forward, dir)) - return state.EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level); - let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)]; - if (!nextSpan && span.level != dir) - return state.EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1, dir); - if (nextSpan && nextSpan.level < span.level) - return state.EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, forward ? 1 : -1, nextSpan.level); - return state.EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level); -} - -const LineBreakPlaceholder = "\uffff"; -class DOMReader { - constructor(points, state$1) { - this.points = points; - this.text = ""; - this.lineSeparator = state$1.facet(state.EditorState.lineSeparator); + /** + Schedule a layout measurement, optionally providing callbacks to + do custom DOM measuring followed by a DOM write phase. Using + this is preferable reading DOM layout directly from, for + example, an event handler, because it'll make sure measuring and + drawing done by other components is synchronized, avoiding + unnecessary DOM layout computations. + */ + requestMeasure(request) { + if (this.measureScheduled < 0) + this.measureScheduled = requestAnimationFrame(() => this.measure()); + if (request) { + if (request.key != null) + for (let i = 0; i < this.measureRequests.length; i++) { + if (this.measureRequests[i].key === request.key) { + this.measureRequests[i] = request; + return; + } + } + this.measureRequests.push(request); + } } - append(text) { - this.text += text; + /** + Collect all values provided by the active plugins for a given + field. + */ + pluginField(field) { + let result = []; + for (let plugin of this.plugins) + plugin.update(this).takeField(field, result); + return result; } - lineBreak() { - this.text += LineBreakPlaceholder; + /** + Get the value of a specific plugin, if present. Note that + plugins that crash can be dropped from a view, so even when you + know you registered a given plugin, it is recommended to check + the return value of this method. + */ + plugin(plugin) { + let known = this.pluginMap.get(plugin); + if (known === undefined || known && known.spec != plugin) + this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null); + return known && known.update(this).value; } - readRange(start, end) { - if (!start) - return this; - let parent = start.parentNode; - for (let cur = start;;) { - this.findPointBefore(parent, cur); - this.readNode(cur); - let next = cur.nextSibling; - if (next == end) - break; - let view = ContentView.get(cur), nextView = ContentView.get(next); - if (view && nextView ? view.breakAfter : - (view ? view.breakAfter : isBlockElement(cur)) || - (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore))) - this.lineBreak(); - cur = next; - } - this.findPointBefore(parent, end); - return this; + /** + The top position of the document, in screen coordinates. This + may be negative when the editor is scrolled down. Points + directly to the top of the first line, not above the padding. + */ + get documentTop() { + return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop; } - readTextNode(node) { - let text = node.nodeValue; - for (let point of this.points) - if (point.node == node) - point.pos = this.text.length + Math.min(point.offset, text.length); - for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) { - let nextBreak = -1, breakSize = 1, m; - if (this.lineSeparator) { - nextBreak = text.indexOf(this.lineSeparator, off); - breakSize = this.lineSeparator.length; - } - else if (m = re.exec(text)) { - nextBreak = m.index; - breakSize = m[0].length; - } - this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak)); - if (nextBreak < 0) - break; - this.lineBreak(); - if (breakSize > 1) - for (let point of this.points) - if (point.node == node && point.pos > this.text.length) - point.pos -= breakSize - 1; - off = nextBreak + breakSize; - } + /** + Reports the padding above and below the document. + */ + get documentPadding() { + return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom }; } - readNode(node) { - if (node.cmIgnore) - return; - let view = ContentView.get(node); - let fromView = view && view.overrideDOMText; - if (fromView != null) { - this.findPointInside(node, fromView.length); - for (let i = fromView.iter(); !i.next().done;) { - if (i.lineBreak) - this.lineBreak(); - else - this.append(i.value); - } - } - else if (node.nodeType == 3) { - this.readTextNode(node); - } - else if (node.nodeName == "BR") { - if (node.nextSibling) - this.lineBreak(); - } - else if (node.nodeType == 1) { - this.readRange(node.firstChild, null); - } + /** + Find the line or block widget at the given vertical position. + + By default, this position is interpreted as a screen position, + meaning `docTop` is set to the DOM top position of the editor + content (forcing a layout). You can pass a different `docTop` + value—for example 0 to interpret `height` as a document-relative + position, or a precomputed document top + (`view.contentDOM.getBoundingClientRect().top`) to limit layout + queries. + + *Deprecated: use `blockAtHeight` instead.* + */ + blockAtHeight(height, docTop) { + let top = ensureTop(docTop, this); + return this.elementAtHeight(height - top).moveY(top); } - findPointBefore(node, next) { - for (let point of this.points) - if (point.node == node && node.childNodes[point.offset] == next) - point.pos = this.text.length; + /** + Find the text line or block widget at the given vertical + position (which is interpreted as relative to the [top of the + document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop) + */ + elementAtHeight(height) { + this.readMeasured(); + return this.viewState.elementAtHeight(height); } - findPointInside(node, maxLen) { - for (let point of this.points) - if (node.nodeType == 3 ? point.node == node : node.contains(point.node)) - point.pos = this.text.length + Math.min(maxLen, point.offset); + /** + Find information for the visual line (see + [`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given + vertical position. The resulting block info might hold another + array of block info structs in its `type` field if this line + consists of more than one block. + + Defaults to treating `height` as a screen position. See + [`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the + interpretation of the `docTop` parameter. + + *Deprecated: use `lineBlockAtHeight` instead.* + */ + visualLineAtHeight(height, docTop) { + let top = ensureTop(docTop, this); + return this.lineBlockAtHeight(height - top).moveY(top); } -} -function isBlockElement(node) { - return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName); -} -class DOMPoint { - constructor(node, offset) { - this.node = node; - this.offset = offset; - this.pos = -1; + /** + Find the line block (see + [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given + height. + */ + lineBlockAtHeight(height) { + this.readMeasured(); + return this.viewState.lineBlockAtHeight(height); } -} - -class DocView extends ContentView { - constructor(view) { - super(); - this.view = view; - this.compositionDeco = Decoration.none; - this.decorations = []; - this.pluginDecorationLength = 0; - // Track a minimum width for the editor. When measuring sizes in - // measureVisibleLineHeights, this is updated to point at the width - // of a given element and its extent in the document. When a change - // happens in that range, these are reset. That way, once we've seen - // a line/element of a given length, we keep the editor wide enough - // to fit at least that element, until it is changed, at which point - // we forget it again. - this.minWidth = 0; - this.minWidthFrom = 0; - this.minWidthTo = 0; - // Track whether the DOM selection was set in a lossy way, so that - // we don't mess it up when reading it back it - this.impreciseAnchor = null; - this.impreciseHead = null; - this.forceSelection = false; - // Used by the resize observer to ignore resizes that we caused - // ourselves - this.lastUpdate = Date.now(); - this.setDOM(view.contentDOM); - this.children = [new LineView]; - this.children[0].setParent(this); - this.updateDeco(); - this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0); + /** + Iterate over the height information of the visual lines in the + viewport. The heights of lines are reported relative to the + given document top, which defaults to the screen position of the + document (forcing a layout). + + *Deprecated: use `viewportLineBlocks` instead.* + */ + viewportLines(f, docTop) { + let top = ensureTop(docTop, this); + for (let line of this.viewportLineBlocks) + f(line.moveY(top)); } - get root() { return this.view.root; } - get editorView() { return this.view; } - get length() { return this.view.state.doc.length; } - // Update the document view to a given state. scrollIntoView can be - // used as a hint to compute a new viewport that includes that - // position, if we know the editor is going to scroll that position - // into view. - update(update) { - let changedRanges = update.changedRanges; - if (this.minWidth > 0 && changedRanges.length) { - if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) { - this.minWidth = this.minWidthFrom = this.minWidthTo = 0; - } - else { - this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1); - this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1); - } - } - if (this.view.inputState.composing < 0) - this.compositionDeco = Decoration.none; - else if (update.transactions.length || this.dirty) - this.compositionDeco = computeCompositionDeco(this.view, update.changes); - // When the DOM nodes around the selection are moved to another - // parent, Chrome sometimes reports a different selection through - // getSelection than the one that it actually shows to the user. - // This forces a selection update when lines are joined to work - // around that. Issue #54 - if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update && - update.state.doc.lines != update.startState.doc.lines) - this.forceSelection = true; - let prevDeco = this.decorations, deco = this.updateDeco(); - let decoDiff = findChangedDeco(prevDeco, deco, update.changes); - changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff); - if (this.dirty == 0 /* Not */ && changedRanges.length == 0) { - return false; - } - else { - this.updateInner(changedRanges, update.startState.doc.length); - if (update.transactions.length) - this.lastUpdate = Date.now(); - return true; - } + /** + Get the extent and vertical position of all [line + blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions + are relative to the [top of the + document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop); + */ + get viewportLineBlocks() { + return this.viewState.viewportLines; } - // Used by update and the constructor do perform the actual DOM - // update - updateInner(changes, oldLength) { - this.view.viewState.mustMeasureContent = true; - this.updateChildren(changes, oldLength); - let { observer } = this.view; - observer.ignore(() => { - // Lock the height during redrawing, since Chrome sometimes - // messes with the scroll position during DOM mutation (though - // no relayout is triggered and I cannot imagine how it can - // recompute the scroll position without a layout) - this.dom.style.height = this.view.viewState.contentHeight + "px"; - this.dom.style.minWidth = this.minWidth ? this.minWidth + "px" : ""; - // Chrome will sometimes, when DOM mutations occur directly - // around the selection, get confused and report a different - // selection from the one it displays (issue #218). This tries - // to detect that situation. - let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined; - this.sync(track); - this.dirty = 0 /* Not */; - if (track && (track.written || observer.selectionRange.focusNode != track.node)) - this.forceSelection = true; - this.dom.style.height = ""; - }); - let gaps = []; - if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length) - for (let child of this.children) - if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget) - gaps.push(child.dom); - observer.updateGaps(gaps); + /** + Find the extent and height of the visual line (a range delimited + on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) + line breaks, or the start/end of the document) at the given position. + + Vertical positions are computed relative to the `docTop` + argument, which defaults to 0 for this method. You can pass + `view.contentDOM.getBoundingClientRect().top` here to get screen + coordinates. + + *Deprecated: use `lineBlockAt` instead.* + */ + visualLineAt(pos, docTop = 0) { + return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop); } - updateChildren(changes, oldLength) { - let cursor = this.childCursor(oldLength); - for (let i = changes.length - 1;; i--) { - let next = i >= 0 ? changes[i] : null; - if (!next) - break; - let { fromA, toA, fromB, toB } = next; - let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.pluginDecorationLength); - let { i: toI, off: toOff } = cursor.findPos(toA, 1); - let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1); - replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd); - } + /** + Find the line block around the given document position. A line + block is a range delimited on both sides by either a + non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) line breaks, or the + start/end of the document. It will usually just hold a line of + text, but may be broken into multiple textblocks by block + widgets. + */ + lineBlockAt(pos) { + return this.viewState.lineBlockAt(pos); } - // Sync the DOM selection to this.state.selection - updateSelection(mustRead = false, fromPointer = false) { - if (mustRead) - this.view.observer.readSelectionRange(); - if (!(fromPointer || this.mayControlSelection()) || - browser.ios && this.view.inputState.rapidCompositionStart) - return; - let force = this.forceSelection; - this.forceSelection = false; - let main = this.view.state.selection.main; - // FIXME need to handle the case where the selection falls inside a block range - let anchor = this.domAtPos(main.anchor); - let head = main.empty ? anchor : this.domAtPos(main.head); - // Always reset on Firefox when next to an uneditable node to - // avoid invisible cursor bugs (#111) - if (browser.gecko && main.empty && betweenUneditable(anchor)) { - let dummy = document.createTextNode(""); - this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null)); - anchor = head = new DOMPos(dummy, 0); - force = true; - } - let domSel = this.view.observer.selectionRange; - // If the selection is already here, or in an equivalent position, don't touch it - if (force || !domSel.focusNode || - !isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) || - !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) { - this.view.observer.ignore(() => { - // Chrome Android will hide the virtual keyboard when tapping - // inside an uneditable node, and not bring it back when we - // move the cursor to its proper position. This tries to - // restore the keyboard by cycling focus. - if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && - inUneditable(domSel.focusNode, this.dom)) { - this.dom.blur(); - this.dom.focus({ preventScroll: true }); - } - let rawSel = getSelection(this.root); - if (main.empty) { - // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076 - if (browser.gecko) { - let nextTo = nextToUneditable(anchor.node, anchor.offset); - if (nextTo && nextTo != (1 /* Before */ | 2 /* After */)) { - let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* Before */ ? 1 : -1); - if (text) - anchor = new DOMPos(text, nextTo == 1 /* Before */ ? 0 : text.nodeValue.length); - } - } - rawSel.collapse(anchor.node, anchor.offset); - if (main.bidiLevel != null && domSel.cursorBidiLevel != null) - domSel.cursorBidiLevel = main.bidiLevel; - } - else if (rawSel.extend) { - // Selection.extend can be used to create an 'inverted' selection - // (one where the focus is before the anchor), but not all - // browsers support it yet. - rawSel.collapse(anchor.node, anchor.offset); - rawSel.extend(head.node, head.offset); - } - else { - // Primitive (IE) way - let range = document.createRange(); - if (main.anchor > main.head) - [anchor, head] = [head, anchor]; - range.setEnd(head.node, head.offset); - range.setStart(anchor.node, anchor.offset); - rawSel.removeAllRanges(); - rawSel.addRange(range); - } - }); - this.view.observer.setSelectionRange(anchor, head); - } - this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset); - this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset); + /** + The editor's total content height. + */ + get contentHeight() { + return this.viewState.contentHeight; } - enforceCursorAssoc() { - if (this.compositionDeco.size) - return; - let cursor = this.view.state.selection.main; - let sel = getSelection(this.root); - if (!cursor.empty || !cursor.assoc || !sel.modify) - return; - let line = LineView.find(this, cursor.head); - if (!line) - return; - let lineStart = line.posAtStart; - if (cursor.head == lineStart || cursor.head == lineStart + line.length) - return; - let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1); - if (!before || !after || before.bottom > after.top) - return; - let dom = this.domAtPos(cursor.head + cursor.assoc); - sel.collapse(dom.node, dom.offset); - sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary"); + /** + Move a cursor position by [grapheme + cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak). `forward` determines whether + the motion is away from the line start, or towards it. Motion in + bidirectional text is in visual order, in the editor's [text + direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). When the start + position was the last one on the line, the returned position + will be across the line break. If there is no further line, the + original position is returned. + + By default, this method moves over a single cluster. The + optional `by` argument can be used to move across more. It will + be called with the first cluster as argument, and should return + a predicate that determines, for each subsequent cluster, + whether it should also be moved over. + */ + moveByChar(start, forward, by) { + return skipAtoms(this, start, moveByChar(this, start, forward, by)); } - mayControlSelection() { - return this.view.state.facet(editable) ? this.root.activeElement == this.dom - : hasSelection(this.dom, this.view.observer.selectionRange); + /** + Move a cursor position across the next group of either + [letters](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) or non-letter + non-whitespace characters. + */ + moveByGroup(start, forward) { + return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial))); } - nearest(dom) { - for (let cur = dom; cur;) { - let domView = ContentView.get(cur); - if (domView && domView.rootView == this) - return domView; - cur = cur.parentNode; - } - return null; + /** + Move to the next line boundary in the given direction. If + `includeWrap` is true, line wrapping is on, and there is a + further wrap point on the current line, the wrap point will be + returned. Otherwise this function will return the start or end + of the line. + */ + moveToLineBoundary(start, forward, includeWrap = true) { + return moveToLineBoundary(this, start, forward, includeWrap); } - posFromDOM(node, offset) { - let view = this.nearest(node); - if (!view) - throw new RangeError("Trying to find position for a DOM position outside of the document"); - return view.localPosFromDOM(node, offset) + view.posAtStart; + /** + Move a cursor position vertically. When `distance` isn't given, + it defaults to moving to the next line (including wrapped + lines). Otherwise, `distance` should provide a positive distance + in pixels. + + When `start` has a + [`goalColumn`](https://codemirror.net/6/docs/ref/#state.SelectionRange.goalColumn), the vertical + motion will use that as a target horizontal position. Otherwise, + the cursor's own horizontal position is used. The returned + cursor will have its goal column set to whichever column was + used. + */ + moveVertically(start, forward, distance) { + return skipAtoms(this, start, moveVertically(this, start, forward, distance)); } + // FIXME remove on next major version + scrollPosIntoView(pos) { + this.dispatch({ effects: scrollTo.of(state.EditorSelection.cursor(pos)) }); + } + /** + Find the DOM parent node and offset (child offset if `node` is + an element, character offset when it is a text node) at the + given document position. + + Note that for positions that aren't currently in + `visibleRanges`, the resulting DOM position isn't necessarily + meaningful (it may just point before or after a placeholder + element). + */ domAtPos(pos) { - let { i, off } = this.childCursor().findPos(pos, -1); - for (; i < this.children.length - 1;) { - let child = this.children[i]; - if (off < child.length || child instanceof LineView) - break; - i++; - off = 0; - } - return this.children[i].domAtPos(off); + return this.docView.domAtPos(pos); } - coordsAt(pos, side) { - for (let off = this.length, i = this.children.length - 1;; i--) { - let child = this.children[i], start = off - child.breakAfter - child.length; - if (pos > start || - (pos == start && child.type != exports.BlockType.WidgetBefore && child.type != exports.BlockType.WidgetAfter && - (!i || side == 2 || this.children[i - 1].breakAfter || - (this.children[i - 1].type == exports.BlockType.WidgetBefore && side > -2)))) - return child.coordsAt(pos - start, side); - off = start; - } + /** + Find the document position at the given DOM node. Can be useful + for associating positions with DOM events. Will raise an error + when `node` isn't part of the editor content. + */ + posAtDOM(node, offset = 0) { + return this.docView.posFromDOM(node, offset); } - measureVisibleLineHeights() { - let result = [], { from, to } = this.view.viewState.viewport; - let contentWidth = this.view.contentDOM.clientWidth; - let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1; - let widest = -1; - for (let pos = 0, i = 0; i < this.children.length; i++) { - let child = this.children[i], end = pos + child.length; - if (end > to) - break; - if (pos >= from) { - let childRect = child.dom.getBoundingClientRect(); - result.push(childRect.height); - if (isWider) { - let last = child.dom.lastChild; - let rects = last ? clientRectsFor(last) : []; - if (rects.length) { - let rect = rects[rects.length - 1]; - let width = this.view.textDirection == exports.Direction.LTR ? rect.right - childRect.left - : childRect.right - rect.left; - if (width > widest) { - widest = width; - this.minWidth = contentWidth; - this.minWidthFrom = pos; - this.minWidthTo = end; - } - } - } - } - pos = end + child.breakAfter; - } - return result; + posAtCoords(coords, precise = true) { + this.readMeasured(); + return posAtCoords(this, coords, precise); } - measureTextSize() { - for (let child of this.children) { - if (child instanceof LineView) { - let measure = child.measureTextSize(); - if (measure) - return measure; - } - } - // If no workable line exists, force a layout of a measurable element - let dummy = document.createElement("div"), lineHeight, charWidth; - dummy.className = "cm-line"; - dummy.textContent = "abc def ghi jkl mno pqr stu"; - this.view.observer.ignore(() => { - this.dom.appendChild(dummy); - let rect = clientRectsFor(dummy.firstChild)[0]; - lineHeight = dummy.getBoundingClientRect().height; - charWidth = rect ? rect.width / 27 : 7; - dummy.remove(); + /** + Get the screen coordinates at the given document position. + `side` determines whether the coordinates are based on the + element before (-1) or after (1) the position (if no element is + available on the given side, the method will transparently use + another strategy to get reasonable coordinates). + */ + coordsAtPos(pos, side = 1) { + this.readMeasured(); + let rect = this.docView.coordsAt(pos, side); + if (!rect || rect.left == rect.right) + return rect; + let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line); + let span = order[BidiSpan.find(order, pos - line.from, -1, side)]; + return flattenRect(rect, (span.dir == exports.Direction.LTR) == (side > 0)); + } + /** + The default width of a character in the editor. May not + accurately reflect the width of all characters (given variable + width fonts or styling of invididual ranges). + */ + get defaultCharacterWidth() { return this.viewState.heightOracle.charWidth; } + /** + The default height of a line in the editor. May not be accurate + for all lines. + */ + get defaultLineHeight() { return this.viewState.heightOracle.lineHeight; } + /** + The text direction + ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction) + CSS property) of the editor. + */ + get textDirection() { return this.viewState.heightOracle.direction; } + /** + Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping) + (as determined by the + [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space) + CSS property of its content element). + */ + get lineWrapping() { return this.viewState.heightOracle.lineWrapping; } + /** + Returns the bidirectional text structure of the given line + (which should be in the current document) as an array of span + objects. The order of these spans matches the [text + direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection)—if that is + left-to-right, the leftmost spans come first, otherwise the + rightmost spans come first. + */ + bidiSpans(line) { + if (line.length > MaxBidiLine) + return trivialOrder(line.length); + let dir = this.textDirection; + for (let entry of this.bidiCache) + if (entry.from == line.from && entry.dir == dir) + return entry.order; + let order = computeOrder(line.text, this.textDirection); + this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order)); + return order; + } + /** + Check whether the editor has focus. + */ + get hasFocus() { + var _a; + // Safari return false for hasFocus when the context menu is open + // or closing, which leads us to ignore selection changes from the + // context menu because it looks like the editor isn't focused. + // This kludges around that. + return (document.hasFocus() || browser.safari && ((_a = this.inputState) === null || _a === void 0 ? void 0 : _a.lastContextMenu) > Date.now() - 3e4) && + this.root.activeElement == this.contentDOM; + } + /** + Put focus on the editor. + */ + focus() { + this.observer.ignore(() => { + focusPreventScroll(this.contentDOM); + this.docView.updateSelection(); }); - return { lineHeight, charWidth }; } - childCursor(pos = this.length) { - // Move back to start of last element when possible, so that - // `ChildCursor.findPos` doesn't have to deal with the edge case - // of being after the last element. - let i = this.children.length; - if (i) - pos -= this.children[--i].length; - return new ChildCursor(this.children, pos, i); + /** + Clean up this editor view, removing its element from the + document, unregistering event handlers, and notifying + plugins. The view instance can no longer be used after + calling this. + */ + destroy() { + for (let plugin of this.plugins) + plugin.destroy(this); + this.plugins = []; + this.inputState.destroy(); + this.dom.remove(); + this.observer.destroy(); + if (this.measureScheduled > -1) + cancelAnimationFrame(this.measureScheduled); + this.destroyed = true; } - computeBlockGapDeco() { - let deco = [], vs = this.view.viewState; - for (let pos = 0, i = 0;; i++) { - let next = i == vs.viewports.length ? null : vs.viewports[i]; - let end = next ? next.from - 1 : this.length; - if (end > pos) { - let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top; - deco.push(Decoration.replace({ widget: new BlockGapWidget(height), block: true, inclusive: true }).range(pos, end)); - } - if (!next) - break; - pos = next.to + 1; - } - return Decoration.set(deco); + /** + Returns an effect that can be + [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to + cause it to scroll the given position or range into view. + */ + static scrollIntoView(pos, options = {}) { + return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? state.EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin)); } - updateDeco() { - let pluginDecorations = this.view.pluginField(PluginField.decorations); - this.pluginDecorationLength = pluginDecorations.length; - return this.decorations = [ - ...pluginDecorations, - ...this.view.state.facet(decorations), - this.compositionDeco, - this.computeBlockGapDeco(), - this.view.viewState.lineGapDeco - ]; + /** + Facet that can be used to add DOM event handlers. The value + should be an object mapping event names to handler functions. The + first such function to return true will be assumed to have handled + that event, and no other handlers or built-in behavior will be + activated for it. + These are registered on the [content + element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except for `scroll` + handlers, which will be called any time the editor's [scroll + element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of its parent nodes + is scrolled. + */ + static domEventHandlers(handlers) { + return ViewPlugin.define(() => ({}), { eventHandlers: handlers }); } - scrollIntoView(target) { - let { range } = target; - let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other; - if (!rect) - return; - if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1))) - rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top), - right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) }; - let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0; - for (let margins of this.view.pluginField(PluginField.scrollMargins)) - if (margins) { - let { left, right, top, bottom } = margins; - if (left != null) - mLeft = Math.max(mLeft, left); - if (right != null) - mRight = Math.max(mRight, right); - if (top != null) - mTop = Math.max(mTop, top); - if (bottom != null) - mBottom = Math.max(mBottom, bottom); - } - let targetRect = { - left: rect.left - mLeft, top: rect.top - mTop, - right: rect.right + mRight, bottom: rect.bottom + mBottom - }; - scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, target.xMargin, target.yMargin, this.view.textDirection == exports.Direction.LTR); + /** + Create a theme extension. The first argument can be a + [`style-mod`](https://github.com/marijnh/style-mod#documentation) + style spec providing the styles for the theme. These will be + prefixed with a generated class for the style. + + Because the selectors will be prefixed with a scope class, rule + that directly match the editor's [wrapper + element](https://codemirror.net/6/docs/ref/#view.EditorView.dom)—to which the scope class will be + added—need to be explicitly differentiated by adding an `&` to + the selector for that element—for example + `&.cm-focused`. + + When `dark` is set to true, the theme will be marked as dark, + which will cause the `&dark` rules from [base + themes](https://codemirror.net/6/docs/ref/#view.EditorView^baseTheme) to be used (as opposed to + `&light` when a light theme is active). + */ + static theme(spec, options) { + let prefix = styleMod.StyleModule.newName(); + let result = [theme.of(prefix), styleModule.of(buildTheme(`.${prefix}`, spec))]; + if (options && options.dark) + result.push(darkTheme.of(true)); + return result; + } + /** + Create an extension that adds styles to the base theme. Like + with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the + place of the editor wrapper element when directly targeting + that. You can also use `&dark` or `&light` instead to only + target editors with a dark or light theme. + */ + static baseTheme(spec) { + return state.Prec.lowest(styleModule.of(buildTheme("." + baseThemeID, spec, lightDarkIDs))); } } -function betweenUneditable(pos) { - return pos.node.nodeType == 1 && pos.node.firstChild && - (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") && - (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false"); +/** +Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a +transaction to make it scroll the given range into view. + +*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead. +*/ +EditorView.scrollTo = scrollTo; +/** +Effect that makes the editor scroll the given range to the +center of the visible view. + +*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead. +*/ +EditorView.centerOn = centerOn; +/** +Facet to add a [style +module](https://github.com/marijnh/style-mod#documentation) to +an editor view. The view will ensure that the module is +mounted in its [document +root](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.root). +*/ +EditorView.styleModule = styleModule; +/** +An input handler can override the way changes to the editable +DOM content are handled. Handlers are passed the document +positions between which the change was found, and the new +content. When one returns true, no further input handlers are +called and the default behavior is prevented. +*/ +EditorView.inputHandler = inputHandler; +/** +Allows you to provide a function that should be called when the +library catches an exception from an extension (mostly from view +plugins, but may be used by other extensions to route exceptions +from user-code-provided callbacks). This is mostly useful for +debugging and logging. See [`logException`](https://codemirror.net/6/docs/ref/#view.logException). +*/ +EditorView.exceptionSink = exceptionSink; +/** +A facet that can be used to register a function to be called +every time the view updates. +*/ +EditorView.updateListener = updateListener; +/** +Facet that controls whether the editor content DOM is editable. +When its highest-precedence value is `false`, the element will +not longer have its `contenteditable` attribute set. (Note that +this doesn't affect API calls that change the editor content, +even when those are bound to keys or buttons. See the +[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.) +*/ +EditorView.editable = editable; +/** +Allows you to influence the way mouse selection happens. The +functions in this facet will be called for a `mousedown` event +on the editor, and can return an object that overrides the way a +selection is computed from that mouse click or drag. +*/ +EditorView.mouseSelectionStyle = mouseSelectionStyle; +/** +Facet used to configure whether a given selection drag event +should move or copy the selection. The given predicate will be +called with the `mousedown` event, and can return `true` when +the drag should move the content. +*/ +EditorView.dragMovesSelection = dragMovesSelection$1; +/** +Facet used to configure whether a given selecting click adds +a new range to the existing selection or replaces it entirely. +*/ +EditorView.clickAddsSelectionRange = clickAddsSelectionRange; +/** +A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration) +are shown in the view. See also [view +plugins](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), which have a separate +mechanism for providing decorations. +*/ +EditorView.decorations = decorations; +/** +This facet records whether a dark theme is active. The extension +returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically +includes an instance of this when the `dark` option is set to +true. +*/ +EditorView.darkTheme = darkTheme; +/** +Facet that provides additional DOM attributes for the editor's +editable DOM element. +*/ +EditorView.contentAttributes = contentAttributes; +/** +Facet that provides DOM attributes for the editor's outer +element. +*/ +EditorView.editorAttributes = editorAttributes; +/** +An extension that enables line wrapping in the editor (by +setting CSS `white-space` to `pre-wrap` in the content). +*/ +EditorView.lineWrapping = EditorView.contentAttributes.of({ "class": "cm-lineWrapping" }); +/** +State effect used to include screen reader announcements in a +transaction. These will be added to the DOM in a visually hidden +element with `aria-live="polite"` set, and should be used to +describe effects that are visually obvious but may not be +noticed by screen reader users (such as moving to the next +search match). +*/ +EditorView.announce = state.StateEffect.define(); +// Maximum line length for which we compute accurate bidi info +const MaxBidiLine = 4096; +// FIXME remove this and its callers on next breaking release +function ensureTop(given, view) { + return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop; +} +let resizeDebounce = -1; +function ensureGlobalHandler() { + window.addEventListener("resize", () => { + if (resizeDebounce == -1) + resizeDebounce = setTimeout(handleResize, 50); + }); } -class BlockGapWidget extends WidgetType { - constructor(height) { - super(); - this.height = height; - } - toDOM() { - let elt = document.createElement("div"); - this.updateDOM(elt); - return elt; - } - eq(other) { return other.height == this.height; } - updateDOM(elt) { - elt.style.height = this.height + "px"; - return true; +function handleResize() { + resizeDebounce = -1; + let found = document.querySelectorAll(".cm-content"); + for (let i = 0; i < found.length; i++) { + let docView = ContentView.get(found[i]); + if (docView) + docView.editorView.requestMeasure(); } - get estimatedHeight() { return this.height; } } -function compositionSurroundingNode(view) { - let sel = view.observer.selectionRange; - let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0); - if (!textNode) - return null; - let cView = view.docView.nearest(textNode); - if (!cView) - return null; - if (cView instanceof LineView) { - let topNode = textNode; - while (topNode.parentNode != cView.dom) - topNode = topNode.parentNode; - let prev = topNode.previousSibling; - while (prev && !ContentView.get(prev)) - prev = prev.previousSibling; - let pos = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart; - return { from: pos, to: pos, node: topNode, text: textNode }; +const BadMeasure = {}; +class CachedOrder { + constructor(from, to, dir, order) { + this.from = from; + this.to = to; + this.dir = dir; + this.order = order; } - else { - for (;;) { - let { parent } = cView; - if (!parent) - return null; - if (parent instanceof LineView) - break; - cView = parent; + static update(cache, changes) { + if (changes.empty) + return cache; + let result = [], lastDir = cache.length ? cache[cache.length - 1].dir : exports.Direction.LTR; + for (let i = Math.max(0, cache.length - 10); i < cache.length; i++) { + let entry = cache[i]; + if (entry.dir == lastDir && !changes.touchesRange(entry.from, entry.to)) + result.push(new CachedOrder(changes.mapPos(entry.from, 1), changes.mapPos(entry.to, -1), entry.dir, entry.order)); } - let from = cView.posAtStart; - return { from, to: from + cView.length, node: cView.dom, text: textNode }; - } -} -function computeCompositionDeco(view, changes) { - let surrounding = compositionSurroundingNode(view); - if (!surrounding) - return Decoration.none; - let { from, to, node, text: textNode } = surrounding; - let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1)); - let { state } = view, text = node.nodeType == 3 ? node.nodeValue : - new DOMReader([], state).readRange(node.firstChild, null).text; - if (newTo - newFrom < text.length) { - if (state.doc.sliceString(newFrom, Math.min(state.doc.length, newFrom + text.length), LineBreakPlaceholder) == text) - newTo = newFrom + text.length; - else if (state.doc.sliceString(Math.max(0, newTo - text.length), newTo, LineBreakPlaceholder) == text) - newFrom = newTo - text.length; - else - return Decoration.none; - } - else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) { - return Decoration.none; + return result; } - return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode) }).range(newFrom, newTo)); } -class CompositionWidget extends WidgetType { - constructor(top, text) { - super(); - this.top = top; - this.text = text; +function attrsFromFacet(view, facet, base) { + for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) { + let source = sources[i], value = typeof source == "function" ? source(view) : source; + if (value) + combineAttrs(value, base); } - eq(other) { return this.top == other.top && this.text == other.text; } - toDOM() { return this.top; } - ignoreEvent() { return false; } - get customView() { return CompositionView; } + return base; } -function nearbyTextNode(node, offset, side) { - for (;;) { - if (node.nodeType == 3) - return node; - if (node.nodeType == 1 && offset > 0 && side <= 0) { - node = node.childNodes[offset - 1]; - offset = maxOffset(node); - } - else if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) { - node = node.childNodes[offset]; - offset = 0; - } - else { - return null; + +const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key"; +function normalizeKeyName(name, platform) { + const parts = name.split(/-(?!$)/); + let result = parts[parts.length - 1]; + if (result == "Space") + result = " "; + let alt, ctrl, shift, meta; + for (let i = 0; i < parts.length - 1; ++i) { + const mod = parts[i]; + if (/^(cmd|meta|m)$/i.test(mod)) + meta = true; + else if (/^a(lt)?$/i.test(mod)) + alt = true; + else if (/^(c|ctrl|control)$/i.test(mod)) + ctrl = true; + else if (/^s(hift)?$/i.test(mod)) + shift = true; + else if (/^mod$/i.test(mod)) { + if (platform == "mac") + meta = true; + else + ctrl = true; } + else + throw new Error("Unrecognized modifier name: " + mod); } + if (alt) + result = "Alt-" + result; + if (ctrl) + result = "Ctrl-" + result; + if (meta) + result = "Meta-" + result; + if (shift) + result = "Shift-" + result; + return result; } -function nextToUneditable(node, offset) { - if (node.nodeType != 1) - return 0; - return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 /* Before */ : 0) | - (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 /* After */ : 0); -} -class DecorationComparator$1 { - constructor() { - this.changes = []; - } - compareRange(from, to) { addRange(from, to, this.changes); } - comparePoint(from, to) { addRange(from, to, this.changes); } -} -function findChangedDeco(a, b, diff) { - let comp = new DecorationComparator$1; - rangeset.RangeSet.compare(a, b, diff, comp); - return comp.changes; +function modifiers(name, event, shift) { + if (event.altKey) + name = "Alt-" + name; + if (event.ctrlKey) + name = "Ctrl-" + name; + if (event.metaKey) + name = "Meta-" + name; + if (shift !== false && event.shiftKey) + name = "Shift-" + name; + return name; } -function inUneditable(node, inside) { - for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) { - if (cur.nodeType == 1 && cur.contentEditable == 'false') { - return true; - } +const handleKeyEvents = EditorView.domEventHandlers({ + keydown(event, view) { + return runHandlers(getKeymap(view.state), event, view, "editor"); } - return false; -} +}); +/** +Facet used for registering keymaps. -function groupAt(state$1, pos, bias = 1) { - let categorize = state$1.charCategorizer(pos); - let line = state$1.doc.lineAt(pos), linePos = pos - line.from; - if (line.length == 0) - return state.EditorSelection.cursor(pos); - if (linePos == 0) - bias = 1; - else if (linePos == line.length) - bias = -1; - let from = linePos, to = linePos; - if (bias < 0) - from = text.findClusterBreak(line.text, linePos, false); - else - to = text.findClusterBreak(line.text, linePos); - let cat = categorize(line.text.slice(from, to)); - while (from > 0) { - let prev = text.findClusterBreak(line.text, from, false); - if (categorize(line.text.slice(prev, from)) != cat) - break; - from = prev; - } - while (to < line.length) { - let next = text.findClusterBreak(line.text, to); - if (categorize(line.text.slice(to, next)) != cat) - break; - to = next; - } - return state.EditorSelection.range(from + line.from, to + line.from); -} -// Search the DOM for the {node, offset} position closest to the given -// coordinates. Very inefficient and crude, but can usually be avoided -// by calling caret(Position|Range)FromPoint instead. -function getdx(x, rect) { - return rect.left > x ? rect.left - x : Math.max(0, x - rect.right); -} -function getdy(y, rect) { - return rect.top > y ? rect.top - y : Math.max(0, y - rect.bottom); -} -function yOverlap(a, b) { - return a.top < b.bottom - 1 && a.bottom > b.top + 1; -} -function upTop(rect, top) { - return top < rect.top ? { top, left: rect.left, right: rect.right, bottom: rect.bottom } : rect; -} -function upBot(rect, bottom) { - return bottom > rect.bottom ? { top: rect.top, left: rect.left, right: rect.right, bottom } : rect; -} -function domPosAtCoords(parent, x, y) { - let closest, closestRect, closestX, closestY; - let above, below, aboveRect, belowRect; - for (let child = parent.firstChild; child; child = child.nextSibling) { - let rects = clientRectsFor(child); - for (let i = 0; i < rects.length; i++) { - let rect = rects[i]; - if (closestRect && yOverlap(closestRect, rect)) - rect = upTop(upBot(rect, closestRect.bottom), closestRect.top); - let dx = getdx(x, rect), dy = getdy(y, rect); - if (dx == 0 && dy == 0) - return child.nodeType == 3 ? domPosInText(child, x, y) : domPosAtCoords(child, x, y); - if (!closest || closestY > dy || closestY == dy && closestX > dx) { - closest = child; - closestRect = rect; - closestX = dx; - closestY = dy; - } - if (dx == 0) { - if (y > rect.bottom && (!aboveRect || aboveRect.bottom < rect.bottom)) { - above = child; - aboveRect = rect; - } - else if (y < rect.top && (!belowRect || belowRect.top > rect.top)) { - below = child; - belowRect = rect; - } - } - else if (aboveRect && yOverlap(aboveRect, rect)) { - aboveRect = upBot(aboveRect, rect.bottom); - } - else if (belowRect && yOverlap(belowRect, rect)) { - belowRect = upTop(belowRect, rect.top); - } - } - } - if (aboveRect && aboveRect.bottom >= y) { - closest = above; - closestRect = aboveRect; - } - else if (belowRect && belowRect.top <= y) { - closest = below; - closestRect = belowRect; - } - if (!closest) - return { node: parent, offset: 0 }; - let clipX = Math.max(closestRect.left, Math.min(closestRect.right, x)); - if (closest.nodeType == 3) - return domPosInText(closest, clipX, y); - if (!closestX && closest.contentEditable == "true") - return domPosAtCoords(closest, clipX, y); - let offset = Array.prototype.indexOf.call(parent.childNodes, closest) + - (x >= (closestRect.left + closestRect.right) / 2 ? 1 : 0); - return { node: parent, offset }; +You can add multiple keymaps to an editor. Their priorities +determine their precedence (the ones specified early or with high +priority get checked first). When a handler has returned `true` +for a given key, no further handlers are called. +*/ +const keymap = state.Facet.define({ enables: handleKeyEvents }); +const Keymaps = new WeakMap(); +// This is hidden behind an indirection, rather than directly computed +// by the facet, to keep internal types out of the facet's type. +function getKeymap(state) { + let bindings = state.facet(keymap); + let map = Keymaps.get(bindings); + if (!map) + Keymaps.set(bindings, map = buildKeymap(bindings.reduce((a, b) => a.concat(b), []))); + return map; } -function domPosInText(node, x, y) { - let len = node.nodeValue.length; - let closestOffset = -1, closestDY = 1e9, generalSide = 0; - for (let i = 0; i < len; i++) { - let rects = textRange(node, i, i + 1).getClientRects(); - for (let j = 0; j < rects.length; j++) { - let rect = rects[j]; - if (rect.top == rect.bottom) - continue; - if (!generalSide) - generalSide = x - rect.left; - let dy = (rect.top > y ? rect.top - y : y - rect.bottom) - 1; - if (rect.left - 1 <= x && rect.right + 1 >= x && dy < closestDY) { - let right = x >= (rect.left + rect.right) / 2, after = right; - if (browser.chrome || browser.gecko) { - // Check for RTL on browsers that support getting client - // rects for empty ranges. - let rectBefore = textRange(node, i).getBoundingClientRect(); - if (rectBefore.left == rect.right) - after = !right; - } - if (dy <= 0) - return { node, offset: i + (after ? 1 : 0) }; - closestOffset = i + (after ? 1 : 0); - closestDY = dy; - } - } - } - return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 }; +/** +Run the key handlers registered for a given scope. The event +object should be `"keydown"` event. Returns true if any of the +handlers handled it. +*/ +function runScopeHandlers(view, event, scope) { + return runHandlers(getKeymap(view.state), event, view, scope); } -function posAtCoords(view, { x, y }, precise, bias = -1) { - var _a; - let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop; - let block, { docHeight } = view.viewState; - let yOffset = y - docTop; - if (yOffset < 0) - return 0; - if (yOffset > docHeight) - return view.state.doc.length; - // Scan for a text block near the queried y position - for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) { - block = view.elementAtHeight(yOffset); - if (block.type == exports.BlockType.Text) - break; - for (;;) { - // Move the y position out of this block - yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine; - if (yOffset >= 0 && yOffset <= docHeight) - break; - // If the document consists entirely of replaced widgets, we - // won't find a text block, so return 0 - if (bounced) - return precise ? null : 0; - bounced = true; - bias = -bias; - } - } - y = docTop + yOffset; - let lineStart = block.from; - // If this is outside of the rendered viewport, we can't determine a position - if (lineStart < view.viewport.from) - return view.viewport.from == 0 ? 0 : precise ? null : posAtCoordsImprecise(view, content, block, x, y); - if (lineStart > view.viewport.to) - return view.viewport.to == view.state.doc.length ? view.state.doc.length : - precise ? null : posAtCoordsImprecise(view, content, block, x, y); - // Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not - let doc = view.dom.ownerDocument; - let root = view.root.elementFromPoint ? view.root : doc; - let element = root.elementFromPoint(x, y); - if (element && !view.contentDOM.contains(element)) - element = null; - // If the element is unexpected, clip x at the sides of the content area and try again - if (!element) { - x = Math.max(content.left + 1, Math.min(content.right - 1, x)); - element = root.elementFromPoint(x, y); - if (element && !view.contentDOM.contains(element)) - element = null; - } - // There's visible editor content under the point, so we can try - // using caret(Position|Range)FromPoint as a shortcut - let node, offset = -1; - if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) { - if (doc.caretPositionFromPoint) { - let pos = doc.caretPositionFromPoint(x, y); - if (pos) - ({ offsetNode: node, offset } = pos); - } - else if (doc.caretRangeFromPoint) { - let range = doc.caretRangeFromPoint(x, y); - if (range) { - ({ startContainer: node, startOffset: offset } = range); - if (browser.safari && isSuspiciousCaretResult(node, offset, x)) - node = undefined; - } +let storedPrefix = null; +const PrefixTimeout = 4000; +function buildKeymap(bindings, platform = currentPlatform) { + let bound = Object.create(null); + let isPrefix = Object.create(null); + let checkPrefix = (name, is) => { + let current = isPrefix[name]; + if (current == null) + isPrefix[name] = is; + else if (current != is) + throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix"); + }; + let add = (scope, key, command, preventDefault) => { + let scopeObj = bound[scope] || (bound[scope] = Object.create(null)); + let parts = key.split(/ (?!$)/).map(k => normalizeKeyName(k, platform)); + for (let i = 1; i < parts.length; i++) { + let prefix = parts.slice(0, i).join(" "); + checkPrefix(prefix, true); + if (!scopeObj[prefix]) + scopeObj[prefix] = { + preventDefault: true, + commands: [(view) => { + let ourObj = storedPrefix = { view, prefix, scope }; + setTimeout(() => { if (storedPrefix == ourObj) + storedPrefix = null; }, PrefixTimeout); + return true; + }] + }; + } + let full = parts.join(" "); + checkPrefix(full, false); + let binding = scopeObj[full] || (scopeObj[full] = { preventDefault: false, commands: [] }); + binding.commands.push(command); + if (preventDefault) + binding.preventDefault = true; + }; + for (let b of bindings) { + let name = b[platform] || b.key; + if (!name) + continue; + for (let scope of b.scope ? b.scope.split(" ") : ["editor"]) { + add(scope, name, b.run, b.preventDefault); + if (b.shift) + add(scope, "Shift-" + name, b.shift, b.preventDefault); } } - // No luck, do our own (potentially expensive) search - if (!node || !view.docView.dom.contains(node)) { - let line = LineView.find(view.docView, lineStart); - if (!line) - return yOffset > block.top + block.height / 2 ? block.to : block.from; - ({ node, offset } = domPosAtCoords(line.dom, x, y)); - } - return view.docView.posFromDOM(node, offset); -} -function posAtCoordsImprecise(view, contentRect, block, x, y) { - let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth); - if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) { - let line = Math.floor((y - block.top) / view.defaultLineHeight); - into += line * view.viewState.heightOracle.lineLength; - } - let content = view.state.sliceDoc(block.from, block.to); - return block.from + text.findColumn(content, into, view.state.tabSize); -} -// In case of a high line height, Safari's caretRangeFromPoint treats -// the space between lines as belonging to the last character of the -// line before. This is used to detect such a result so that it can be -// ignored (issue #401). -function isSuspiciousCaretResult(node, offset, x) { - let len; - if (node.nodeType != 3 || offset != (len = node.nodeValue.length)) - return false; - for (let next = node.nextSibling; next; next = next.nextSibling) - if (next.nodeType != 1 || next.nodeName != "BR") - return false; - return textRange(node, len - 1, len).getBoundingClientRect().left > x; + return bound; } -function moveToLineBoundary(view, start, forward, includeWrap) { - let line = view.state.doc.lineAt(start.head); - let coords = !includeWrap || !view.lineWrapping ? null - : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head); - if (coords) { - let editorRect = view.dom.getBoundingClientRect(); - let pos = view.posAtCoords({ x: forward == (view.textDirection == exports.Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1, - y: (coords.top + coords.bottom) / 2 }); - if (pos != null) - return state.EditorSelection.cursor(pos, forward ? -1 : 1); +function runHandlers(map, event, view, scope) { + let name = w3cKeyname.keyName(event), isChar = name.length == 1 && name != " "; + let prefix = "", fallthrough = false; + if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) { + prefix = storedPrefix.prefix + " "; + if (fallthrough = modifierCodes.indexOf(event.keyCode) < 0) + storedPrefix = null; } - let lineView = LineView.find(view.docView, start.head); - let end = lineView ? (forward ? lineView.posAtEnd : lineView.posAtStart) : (forward ? line.to : line.from); - return state.EditorSelection.cursor(end, forward ? -1 : 1); -} -function moveByChar(view, start, forward, by) { - let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line); - for (let cur = start, check = null;;) { - let next = moveVisually(line, spans, view.textDirection, cur, forward), char = movedOver; - if (!next) { - if (line.number == (forward ? view.state.doc.lines : 1)) - return cur; - char = "\n"; - line = view.state.doc.line(line.number + (forward ? 1 : -1)); - spans = view.bidiSpans(line); - next = state.EditorSelection.cursor(forward ? line.from : line.to); + let runFor = (binding) => { + if (binding) { + for (let cmd of binding.commands) + if (cmd(view)) + return true; + if (binding.preventDefault) + fallthrough = true; } - if (!check) { - if (!by) - return next; - check = by(char); + return false; + }; + let scopeObj = map[scope], baseName; + if (scopeObj) { + if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)])) + return true; + if (isChar && (event.shiftKey || event.altKey || event.metaKey) && + (baseName = w3cKeyname.base[event.keyCode]) && baseName != name) { + if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) + return true; } - else if (!check(char)) { - return cur; + else if (isChar && event.shiftKey) { + if (runFor(scopeObj[prefix + modifiers(name, event, true)])) + return true; } - cur = next; } + return fallthrough; } -function byGroup(view, pos, start) { - let categorize = view.state.charCategorizer(pos); - let cat = categorize(start); - return (next) => { - let nextCat = categorize(next); - if (cat == state.CharCategory.Space) - cat = nextCat; - return cat == nextCat; - }; + +const CanHidePrimary = !browser.ios; // FIXME test IE +const selectionConfig = state.Facet.define({ + combine(configs) { + return state.combineConfig(configs, { + cursorBlinkRate: 1200, + drawRangeCursor: true + }, { + cursorBlinkRate: (a, b) => Math.min(a, b), + drawRangeCursor: (a, b) => a || b + }); + } +}); +/** +Returns an extension that hides the browser's native selection and +cursor, replacing the selection with a background behind the text +(with the `cm-selectionBackground` class), and the +cursors with elements overlaid over the code (using +`cm-cursor-primary` and `cm-cursor-secondary`). + +This allows the editor to display secondary selection ranges, and +tends to produce a type of selection more in line with that users +expect in a text editor (the native selection styling will often +leave gaps between lines and won't fill the horizontal space after +a line when the selection continues past it). + +It does have a performance cost, in that it requires an extra DOM +layout cycle for many updates (the selection is drawn based on DOM +layout information that's only available after laying out the +content). +*/ +function drawSelection(config = {}) { + return [ + selectionConfig.of(config), + drawSelectionPlugin, + hideNativeSelection + ]; } -function moveVertically(view, start, forward, distance) { - let startPos = start.head, dir = forward ? 1 : -1; - if (startPos == (forward ? view.state.doc.length : 0)) - return state.EditorSelection.cursor(startPos, start.assoc); - let goal = start.goalColumn, startY; - let rect = view.contentDOM.getBoundingClientRect(); - let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop; - if (startCoords) { - if (goal == null) - goal = startCoords.left - rect.left; - startY = dir < 0 ? startCoords.top : startCoords.bottom; +class Piece { + constructor(left, top, width, height, className) { + this.left = left; + this.top = top; + this.width = width; + this.height = height; + this.className = className; } - else { - let line = view.viewState.lineBlockAt(startPos - docTop); - if (goal == null) - goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from)); - startY = (dir < 0 ? line.top : line.bottom) + docTop; + draw() { + let elt = document.createElement("div"); + elt.className = this.className; + this.adjust(elt); + return elt; } - let resolvedGoal = rect.left + goal; - let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1); - for (let extra = 0;; extra += 10) { - let curY = startY + (dist + extra) * dir; - let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir); - if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos)) - return state.EditorSelection.cursor(pos, start.assoc, undefined, goal); + adjust(elt) { + elt.style.left = this.left + "px"; + elt.style.top = this.top + "px"; + if (this.width >= 0) + elt.style.width = this.width + "px"; + elt.style.height = this.height + "px"; } -} -function skipAtoms(view, oldPos, pos) { - let atoms = view.pluginField(PluginField.atomicRanges); - for (;;) { - let moved = false; - for (let set of atoms) { - set.between(pos.from - 1, pos.from + 1, (from, to, value) => { - if (pos.from > from && pos.from < to) { - pos = oldPos.from > pos.from ? state.EditorSelection.cursor(from, 1) : state.EditorSelection.cursor(to, -1); - moved = true; - } - }); - } - if (!moved) - return pos; + eq(p) { + return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height && + this.className == p.className; } } - -// This will also be where dragging info and such goes -class InputState { +const drawSelectionPlugin = ViewPlugin.fromClass(class { constructor(view) { - this.lastKeyCode = 0; - this.lastKeyTime = 0; - // On iOS, some keys need to have their default behavior happen - // (after which we retroactively handle them and reset the DOM) to - // avoid messing up the virtual keyboard state. - this.pendingIOSKey = undefined; - this.lastSelectionOrigin = null; - this.lastSelectionTime = 0; - this.lastEscPress = 0; - this.lastContextMenu = 0; - this.scrollHandlers = []; - this.registeredEvents = []; - this.customHandlers = []; - // -1 means not in a composition. Otherwise, this counts the number - // of changes made during the composition. The count is used to - // avoid treating the start state of the composition, before any - // changes have been made, as part of the composition. - this.composing = -1; - // Tracks whether the next change should be marked as starting the - // composition (null means no composition, true means next is the - // first, false means first has already been marked for this - // composition) - this.compositionFirstChange = null; - this.compositionEndedAt = 0; - this.rapidCompositionStart = false; - this.mouseSelection = null; - for (let type in handlers) { - let handler = handlers[type]; - view.contentDOM.addEventListener(type, (event) => { - if (type == "keydown" && this.keydown(view, event)) - return; - if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event)) - return; - if (this.mustFlushObserver(event)) - view.observer.forceFlush(); - if (this.runCustomHandlers(type, view, event)) - event.preventDefault(); - else - handler(view, event); - }); - this.registeredEvents.push(type); - } - this.notifiedFocused = view.hasFocus; - this.ensureHandlers(view); - // On Safari adding an input event handler somehow prevents an - // issue where the composition vanishes when you press enter. - if (browser.safari) - view.contentDOM.addEventListener("input", () => null); + this.view = view; + this.rangePieces = []; + this.cursors = []; + this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) }; + this.selectionLayer = view.scrollDOM.appendChild(document.createElement("div")); + this.selectionLayer.className = "cm-selectionLayer"; + this.selectionLayer.setAttribute("aria-hidden", "true"); + this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div")); + this.cursorLayer.className = "cm-cursorLayer"; + this.cursorLayer.setAttribute("aria-hidden", "true"); + view.requestMeasure(this.measureReq); + this.setBlinkRate(); } - setSelectionOrigin(origin) { - this.lastSelectionOrigin = origin; - this.lastSelectionTime = Date.now(); + setBlinkRate() { + this.cursorLayer.style.animationDuration = this.view.state.facet(selectionConfig).cursorBlinkRate + "ms"; } - ensureHandlers(view) { - let handlers = this.customHandlers = view.pluginField(domEventHandlers); - for (let set of handlers) { - for (let type in set.handlers) - if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") { - this.registeredEvents.push(type); - view.contentDOM.addEventListener(type, (event) => { - if (!eventBelongsToEditor(view, event)) - return; - if (this.runCustomHandlers(type, view, event)) - event.preventDefault(); - }); - } - } + update(update) { + let confChanged = update.startState.facet(selectionConfig) != update.state.facet(selectionConfig); + if (confChanged || update.selectionSet || update.geometryChanged || update.viewportChanged) + this.view.requestMeasure(this.measureReq); + if (update.transactions.some(tr => tr.scrollIntoView)) + this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink"; + if (confChanged) + this.setBlinkRate(); } - runCustomHandlers(type, view, event) { - for (let set of this.customHandlers) { - let handler = set.handlers[type]; - if (handler) { - try { - if (handler.call(set.plugin, event, view) || event.defaultPrevented) - return true; - } - catch (e) { - logException(view.state, e); - } + readPos() { + let { state } = this.view, conf = state.facet(selectionConfig); + let rangePieces = state.selection.ranges.map(r => r.empty ? [] : measureRange(this.view, r)).reduce((a, b) => a.concat(b)); + let cursors = []; + for (let r of state.selection.ranges) { + let prim = r == state.selection.main; + if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) { + let piece = measureCursor(this.view, r, prim); + if (piece) + cursors.push(piece); } } - return false; + return { rangePieces, cursors }; } - runScrollHandlers(view, event) { - for (let set of this.customHandlers) { - let handler = set.handlers.scroll; - if (handler) { - try { - handler.call(set.plugin, event, view); - } - catch (e) { - logException(view.state, e); - } + drawSel({ rangePieces, cursors }) { + if (rangePieces.length != this.rangePieces.length || rangePieces.some((p, i) => !p.eq(this.rangePieces[i]))) { + this.selectionLayer.textContent = ""; + for (let p of rangePieces) + this.selectionLayer.appendChild(p.draw()); + this.rangePieces = rangePieces; + } + if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) { + let oldCursors = this.cursorLayer.children; + if (oldCursors.length !== cursors.length) { + this.cursorLayer.textContent = ""; + for (const c of cursors) + this.cursorLayer.appendChild(c.draw()); + } + else { + cursors.forEach((c, idx) => c.adjust(oldCursors[idx])); } + this.cursors = cursors; } } - keydown(view, event) { - // Must always run, even if a custom handler handled the event - this.lastKeyCode = event.keyCode; - this.lastKeyTime = Date.now(); - if (this.screenKeyEvent(view, event)) - return true; - // Chrome for Android usually doesn't fire proper key events, but - // occasionally does, usually surrounded by a bunch of complicated - // composition changes. When an enter or backspace key event is - // seen, hold off on handling DOM events for a bit, and then - // dispatch it. - if (browser.android && browser.chrome && !event.synthetic && - (event.keyCode == 13 || event.keyCode == 8)) { - view.observer.delayAndroidKey(event.key, event.keyCode); - return true; - } - // Prevent the default behavior of Enter on iOS makes the - // virtual keyboard get stuck in the wrong (lowercase) - // state. So we let it go through, and then, in - // applyDOMChange, notify key handlers of it and reset to - // the state they produce. - let pending; - if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && - !(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) { - this.pendingIOSKey = pending; - setTimeout(() => this.flushIOSKey(view), 250); - return true; - } - return false; + destroy() { + this.selectionLayer.remove(); + this.cursorLayer.remove(); } - flushIOSKey(view) { - let key = this.pendingIOSKey; - if (!key) - return false; - this.pendingIOSKey = undefined; - return dispatchKey(view.contentDOM, key.key, key.keyCode); +}); +const themeSpec = { + ".cm-line": { + "& ::selection": { backgroundColor: "transparent !important" }, + "&::selection": { backgroundColor: "transparent !important" } } - ignoreDuringComposition(event) { - if (!/^key/.test(event.type)) - return false; - if (this.composing > 0) - return true; - // See https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/. - // On some input method editors (IMEs), the Enter key is used to - // confirm character selection. On Safari, when Enter is pressed, - // compositionend and keydown events are sometimes emitted in the - // wrong order. The key event should still be ignored, even when - // it happens after the compositionend event. - if (browser.safari && Date.now() - this.compositionEndedAt < 500) { - this.compositionEndedAt = 0; - return true; +}; +if (CanHidePrimary) + themeSpec[".cm-line"].caretColor = "transparent !important"; +const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec)); +function getBase(view) { + let rect = view.scrollDOM.getBoundingClientRect(); + let left = view.textDirection == exports.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth; + return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop }; +} +function wrappedLine(view, pos, inside) { + let range = state.EditorSelection.cursor(pos); + return { from: Math.max(inside.from, view.moveToLineBoundary(range, false, true).from), + to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from), + type: exports.BlockType.Text }; +} +function blockAt(view, pos) { + let line = view.lineBlockAt(pos); + if (Array.isArray(line.type)) + for (let l of line.type) { + if (l.to > pos || l.to == pos && (l.to == line.to || l.type == exports.BlockType.Text)) + return l; } - return false; + return line; +} +function measureRange(view, range) { + if (range.to <= view.viewport.from || range.from >= view.viewport.to) + return []; + let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to); + let ltr = view.textDirection == exports.Direction.LTR; + let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view); + let lineStyle = window.getComputedStyle(content.firstChild); + let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent)); + let rightSide = contentRect.right - parseInt(lineStyle.paddingRight); + let startBlock = blockAt(view, from), endBlock = blockAt(view, to); + let visualStart = startBlock.type == exports.BlockType.Text ? startBlock : null; + let visualEnd = endBlock.type == exports.BlockType.Text ? endBlock : null; + if (view.lineWrapping) { + if (visualStart) + visualStart = wrappedLine(view, from, visualStart); + if (visualEnd) + visualEnd = wrappedLine(view, to, visualEnd); } - screenKeyEvent(view, event) { - let protectedTab = event.keyCode == 9 && Date.now() < this.lastEscPress + 2000; - if (event.keyCode == 27) - this.lastEscPress = Date.now(); - else if (modifierCodes.indexOf(event.keyCode) < 0) - this.lastEscPress = 0; - return protectedTab; + if (visualStart && visualEnd && visualStart.from == visualEnd.from) { + return pieces(drawForLine(range.from, range.to, visualStart)); } - mustFlushObserver(event) { - return (event.type == "keydown" && event.keyCode != 229) || - event.type == "compositionend" && !browser.ios; + else { + let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false); + let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true); + let between = []; + if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1) + between.push(piece(leftSide, top.bottom, rightSide, bottom.top)); + else if (top.bottom < bottom.top && view.elementAtHeight((top.bottom + bottom.top) / 2).type == exports.BlockType.Text) + top.bottom = bottom.top = (top.bottom + bottom.top) / 2; + return pieces(top).concat(between).concat(pieces(bottom)); } - startMouseSelection(mouseSelection) { - if (this.mouseSelection) - this.mouseSelection.destroy(); - this.mouseSelection = mouseSelection; + function piece(left, top, right, bottom) { + return new Piece(left - base.left, top - base.top, right - left, bottom - top, "cm-selectionBackground"); } - update(update) { - if (this.mouseSelection) - this.mouseSelection.update(update); - if (update.transactions.length) - this.lastKeyCode = this.lastSelectionTime = 0; + function pieces({ top, bottom, horizontal }) { + let pieces = []; + for (let i = 0; i < horizontal.length; i += 2) + pieces.push(piece(horizontal[i], top, horizontal[i + 1], bottom)); + return pieces; + } + // Gets passed from/to in line-local positions + function drawForLine(from, to, line) { + let top = 1e9, bottom = -1e9, horizontal = []; + function addSpan(from, fromOpen, to, toOpen, dir) { + // Passing 2/-2 is a kludge to force the view to return + // coordinates on the proper side of block widgets, since + // normalizing the side there, though appropriate for most + // coordsAtPos queries, would break selection drawing. + let fromCoords = view.coordsAtPos(from, (from == line.to ? -2 : 2)); + let toCoords = view.coordsAtPos(to, (to == line.from ? 2 : -2)); + top = Math.min(fromCoords.top, toCoords.top, top); + bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom); + if (dir == exports.Direction.LTR) + horizontal.push(ltr && fromOpen ? leftSide : fromCoords.left, ltr && toOpen ? rightSide : toCoords.right); + else + horizontal.push(!ltr && toOpen ? leftSide : toCoords.left, !ltr && fromOpen ? rightSide : fromCoords.right); + } + let start = from !== null && from !== void 0 ? from : line.from, end = to !== null && to !== void 0 ? to : line.to; + // Split the range by visible range and document line + for (let r of view.visibleRanges) + if (r.to > start && r.from < end) { + for (let pos = Math.max(r.from, start), endPos = Math.min(r.to, end);;) { + let docLine = view.state.doc.lineAt(pos); + for (let span of view.bidiSpans(docLine)) { + let spanFrom = span.from + docLine.from, spanTo = span.to + docLine.from; + if (spanFrom >= endPos) + break; + if (spanTo > pos) + addSpan(Math.max(spanFrom, pos), from == null && spanFrom <= start, Math.min(spanTo, endPos), to == null && spanTo >= end, span.dir); + } + pos = docLine.to + 1; + if (pos >= endPos) + break; + } + } + if (horizontal.length == 0) + addSpan(start, from == null, end, to == null, view.textDirection); + return { top, bottom, horizontal }; } - destroy() { - if (this.mouseSelection) - this.mouseSelection.destroy(); + function drawForWidget(block, top) { + let y = contentRect.top + (top ? block.top : block.bottom); + return { top: y, bottom: y, horizontal: [] }; } } -const PendingKeys = [ - { key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" }, - { key: "Enter", keyCode: 13, inputType: "insertParagraph" }, - { key: "Delete", keyCode: 46, inputType: "deleteContentForward" } -]; -// Key codes for modifier keys -const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225]; -class MouseSelection { - constructor(view, startEvent, style, mustSelect) { +function measureCursor(view, cursor, primary) { + let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1); + if (!pos) + return null; + let base = getBase(view); + return new Piece(pos.left - base.left, pos.top - base.top, -1, pos.bottom - pos.top, primary ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary"); +} + +const setDropCursorPos = state.StateEffect.define({ + map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); } +}); +const dropCursorPos = state.StateField.define({ + create() { return null; }, + update(pos, tr) { + if (pos != null) + pos = tr.changes.mapPos(pos); + return tr.effects.reduce((pos, e) => e.is(setDropCursorPos) ? e.value : pos, pos); + } +}); +const drawDropCursor = ViewPlugin.fromClass(class { + constructor(view) { this.view = view; - this.style = style; - this.mustSelect = mustSelect; - this.lastEvent = startEvent; - let doc = view.contentDOM.ownerDocument; - doc.addEventListener("mousemove", this.move = this.move.bind(this)); - doc.addEventListener("mouseup", this.up = this.up.bind(this)); - this.extend = startEvent.shiftKey; - this.multiple = view.state.facet(state.EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent); - this.dragMove = dragMovesSelection(view, startEvent); - this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false; - // When clicking outside of the selection, immediately apply the - // effect of starting the selection - if (this.dragging === false) { - startEvent.preventDefault(); - this.select(startEvent); + this.cursor = null; + this.measureReq = { read: this.readPos.bind(this), write: this.drawCursor.bind(this) }; + } + update(update) { + var _a; + let cursorPos = update.state.field(dropCursorPos); + if (cursorPos == null) { + if (this.cursor != null) { + (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.remove(); + this.cursor = null; + } + } + else { + if (!this.cursor) { + this.cursor = this.view.scrollDOM.appendChild(document.createElement("div")); + this.cursor.className = "cm-dropCursor"; + } + if (update.startState.field(dropCursorPos) != cursorPos || update.docChanged || update.geometryChanged) + this.view.requestMeasure(this.measureReq); } } - move(event) { - if (event.buttons == 0) - return this.destroy(); - if (this.dragging !== false) - return; - this.select(this.lastEvent = event); + readPos() { + let pos = this.view.state.field(dropCursorPos); + let rect = pos != null && this.view.coordsAtPos(pos); + if (!rect) + return null; + let outer = this.view.scrollDOM.getBoundingClientRect(); + return { + left: rect.left - outer.left + this.view.scrollDOM.scrollLeft, + top: rect.top - outer.top + this.view.scrollDOM.scrollTop, + height: rect.bottom - rect.top + }; } - up(event) { - if (this.dragging == null) - this.select(this.lastEvent); - if (!this.dragging) - event.preventDefault(); - this.destroy(); + drawCursor(pos) { + if (this.cursor) { + if (pos) { + this.cursor.style.left = pos.left + "px"; + this.cursor.style.top = pos.top + "px"; + this.cursor.style.height = pos.height + "px"; + } + else { + this.cursor.style.left = "-100000px"; + } + } } destroy() { - let doc = this.view.contentDOM.ownerDocument; - doc.removeEventListener("mousemove", this.move); - doc.removeEventListener("mouseup", this.up); - this.view.inputState.mouseSelection = null; + if (this.cursor) + this.cursor.remove(); } - select(event) { - let selection = this.style.get(event, this.extend, this.multiple); - if (this.mustSelect || !selection.eq(this.view.state.selection) || - selection.main.assoc != this.view.state.selection.main.assoc) - this.view.dispatch({ - selection, - userEvent: "select.pointer", - scrollIntoView: true - }); - this.mustSelect = false; + setDropPos(pos) { + if (this.view.state.field(dropCursorPos) != pos) + this.view.dispatch({ effects: setDropCursorPos.of(pos) }); } - update(update) { - if (update.docChanged && this.dragging) - this.dragging = this.dragging.map(update.changes); - if (this.style.update(update)) - setTimeout(() => this.select(this.lastEvent), 20); +}, { + eventHandlers: { + dragover(event) { + this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY })); + }, + dragleave(event) { + if (event.target == this.view.contentDOM || !this.view.contentDOM.contains(event.relatedTarget)) + this.setDropPos(null); + }, + dragend() { + this.setDropPos(null); + }, + drop() { + this.setDropPos(null); + } } +}); +/** +Draws a cursor at the current drop position when something is +dragged over the editor. +*/ +function dropCursor() { + return [dropCursorPos, drawDropCursor]; } -function addsSelectionRange(view, event) { - let facet = view.state.facet(clickAddsSelectionRange); - return facet.length ? facet[0](event) : browser.mac ? event.metaKey : event.ctrlKey; -} -function dragMovesSelection(view, event) { - let facet = view.state.facet(dragMovesSelection$1); - return facet.length ? facet[0](event) : browser.mac ? !event.altKey : !event.ctrlKey; -} -function isInPrimarySelection(view, event) { - let { main } = view.state.selection; - if (main.empty) - return false; - // On boundary clicks, check whether the coordinates are inside the - // selection's client rectangles - let sel = getSelection(view.root); - if (sel.rangeCount == 0) - return true; - let rects = sel.getRangeAt(0).getClientRects(); - for (let i = 0; i < rects.length; i++) { - let rect = rects[i]; - if (rect.left <= event.clientX && rect.right >= event.clientX && - rect.top <= event.clientY && rect.bottom >= event.clientY) - return true; + +function iterMatches(doc, re, from, to, f) { + re.lastIndex = 0; + for (let cursor = doc.iterRange(from, to), pos = from, m; !cursor.next().done; pos += cursor.value.length) { + if (!cursor.lineBreak) + while (m = re.exec(cursor.value)) + f(pos + m.index, pos + m.index + m[0].length, m); } - return false; -} -function eventBelongsToEditor(view, event) { - if (!event.bubbles) - return true; - if (event.defaultPrevented) - return false; - for (let node = event.target, cView; node != view.contentDOM; node = node.parentNode) - if (!node || node.nodeType == 11 || ((cView = ContentView.get(node)) && cView.ignoreEvent(event))) - return false; - return true; -} -const handlers = Object.create(null); -// This is very crude, but unfortunately both these browsers _pretend_ -// that they have a clipboard API—all the objects and methods are -// there, they just don't work, and they are hard to test. -const brokenClipboardAPI = (browser.ie && browser.ie_version < 15) || - (browser.ios && browser.webkit_version < 604); -function capturePaste(view) { - let parent = view.dom.parentNode; - if (!parent) - return; - let target = parent.appendChild(document.createElement("textarea")); - target.style.cssText = "position: fixed; left: -10000px; top: 10px"; - target.focus(); - setTimeout(() => { - view.focus(); - target.remove(); - doPaste(view, target.value); - }, 50); } -function doPaste(view, input) { - let { state: state$1 } = view, changes, i = 1, text = state$1.toText(input); - let byLine = text.lines == state$1.selection.ranges.length; - let linewise = lastLinewiseCopy != null && state$1.selection.ranges.every(r => r.empty) && lastLinewiseCopy == text.toString(); - if (linewise) { - let lastLine = -1; - changes = state$1.changeByRange(range => { - let line = state$1.doc.lineAt(range.from); - if (line.from == lastLine) - return { range }; - lastLine = line.from; - let insert = state$1.toText((byLine ? text.line(i++).text : input) + state$1.lineBreak); - return { changes: { from: line.from, insert }, - range: state.EditorSelection.cursor(range.from + insert.length) }; - }); - } - else if (byLine) { - changes = state$1.changeByRange(range => { - let line = text.line(i++); - return { changes: { from: range.from, to: range.to, insert: line.text }, - range: state.EditorSelection.cursor(range.from + line.length) }; - }); - } - else { - changes = state$1.replaceSelection(text); +function matchRanges(view, maxLength) { + let visible = view.visibleRanges; + if (visible.length == 1 && visible[0].from == view.viewport.from && + visible[0].to == view.viewport.to) + return visible; + let result = []; + for (let { from, to } of visible) { + from = Math.max(view.state.doc.lineAt(from).from, from - maxLength); + to = Math.min(view.state.doc.lineAt(to).to, to + maxLength); + if (result.length && result[result.length - 1].to >= from) + result[result.length - 1].to = to; + else + result.push({ from, to }); } - view.dispatch(changes, { - userEvent: "input.paste", - scrollIntoView: true - }); + return result; } -handlers.keydown = (view, event) => { - view.inputState.setSelectionOrigin("select"); -}; -let lastTouch = 0; -handlers.touchstart = (view, e) => { - lastTouch = Date.now(); - view.inputState.setSelectionOrigin("select.pointer"); -}; -handlers.touchmove = view => { - view.inputState.setSelectionOrigin("select.pointer"); -}; -handlers.mousedown = (view, event) => { - view.observer.flush(); - if (lastTouch > Date.now() - 2000 && getClickType(event) == 1) - return; // Ignore touch interaction - let style = null; - for (let makeStyle of view.state.facet(mouseSelectionStyle)) { - style = makeStyle(view, event); - if (style) - break; - } - if (!style && event.button == 0) - style = basicMouseSelection(view, event); - if (style) { - let mustFocus = view.root.activeElement != view.contentDOM; - if (mustFocus) - view.observer.ignore(() => focusPreventScroll(view.contentDOM)); - view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus)); +/** +Helper class used to make it easier to maintain decorations on +visible code that matches a given regular expression. To be used +in a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin). Instances of this object +represent a matching configuration. +*/ +class MatchDecorator { + /** + Create a decorator. + */ + constructor(config) { + let { regexp, decoration, boundary, maxLength = 1000 } = config; + if (!regexp.global) + throw new RangeError("The regular expression given to MatchDecorator should have its 'g' flag set"); + this.regexp = regexp; + this.getDeco = typeof decoration == "function" ? decoration : () => decoration; + this.boundary = boundary; + this.maxLength = maxLength; } -}; -function rangeForClick(view, pos, bias, type) { - if (type == 1) { // Single click - return state.EditorSelection.cursor(pos, bias); + /** + Compute the full set of decorations for matches in the given + view's viewport. You'll want to call this when initializing your + plugin. + */ + createDeco(view) { + let build = new rangeset.RangeSetBuilder(); + for (let { from, to } of matchRanges(view, this.maxLength)) + iterMatches(view.state.doc, this.regexp, from, to, (a, b, m) => build.add(a, b, this.getDeco(m, view, a))); + return build.finish(); } - else if (type == 2) { // Double click - return groupAt(view.state, pos, bias); + /** + Update a set of decorations for a view update. `deco` _must_ be + the set of decorations produced by _this_ `MatchDecorator` for + the view state before the update. + */ + updateDeco(update, deco) { + let changeFrom = 1e9, changeTo = -1; + if (update.docChanged) + update.changes.iterChanges((_f, _t, from, to) => { + if (to > update.view.viewport.from && from < update.view.viewport.to) { + changeFrom = Math.min(from, changeFrom); + changeTo = Math.max(to, changeTo); + } + }); + if (update.viewportChanged || changeTo - changeFrom > 1000) + return this.createDeco(update.view); + if (changeTo > -1) + return this.updateRange(update.view, deco.map(update.changes), changeFrom, changeTo); + return deco; } - else { // Triple click - let visual = LineView.find(view.docView, pos), line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos); - let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to; - if (to < view.state.doc.length && to == line.to) - to++; - return state.EditorSelection.range(from, to); + updateRange(view, deco, updateFrom, updateTo) { + for (let r of view.visibleRanges) { + let from = Math.max(r.from, updateFrom), to = Math.min(r.to, updateTo); + if (to > from) { + let fromLine = view.state.doc.lineAt(from), toLine = fromLine.to < to ? view.state.doc.lineAt(to) : fromLine; + let start = Math.max(r.from, fromLine.from), end = Math.min(r.to, toLine.to); + if (this.boundary) { + for (; from > fromLine.from; from--) + if (this.boundary.test(fromLine.text[from - 1 - fromLine.from])) { + start = from; + break; + } + for (; to < toLine.to; to++) + if (this.boundary.test(toLine.text[to - toLine.from])) { + end = to; + break; + } + } + let ranges = [], m; + if (fromLine == toLine) { + this.regexp.lastIndex = start - fromLine.from; + while ((m = this.regexp.exec(fromLine.text)) && m.index < end - fromLine.from) { + let pos = m.index + fromLine.from; + ranges.push(this.getDeco(m, view, pos).range(pos, pos + m[0].length)); + } + } + else { + iterMatches(view.state.doc, this.regexp, start, end, (from, to, m) => ranges.push(this.getDeco(m, view, from).range(from, to))); + } + deco = deco.update({ filterFrom: start, filterTo: end, filter: (from, to) => from < start || to > end, add: ranges }); + } + } + return deco; } } -let insideY = (y, rect) => y >= rect.top && y <= rect.bottom; -let inside = (x, y, rect) => insideY(y, rect) && x >= rect.left && x <= rect.right; -// Try to determine, for the given coordinates, associated with the -// given position, whether they are related to the element before or -// the element after the position. -function findPositionSide(view, pos, x, y) { - let line = LineView.find(view.docView, pos); - if (!line) - return 1; - let off = pos - line.posAtStart; - // Line boundaries point into the line - if (off == 0) - return 1; - if (off == line.length) - return -1; - // Positions on top of an element point at that element - let before = line.coordsAt(off, -1); - if (before && inside(x, y, before)) - return -1; - let after = line.coordsAt(off, 1); - if (after && inside(x, y, after)) - return 1; - // This is probably a line wrap point. Pick before if the point is - // beside it. - return before && insideY(y, before) ? -1 : 1; -} -function queryPos(view, event) { - let pos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false); - return { pos, bias: findPositionSide(view, pos, event.clientX, event.clientY) }; + +const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g"; +const Specials = new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport); +const Names = { + 0: "null", + 7: "bell", + 8: "backspace", + 10: "newline", + 11: "vertical tab", + 13: "carriage return", + 27: "escape", + 8203: "zero width space", + 8204: "zero width non-joiner", + 8205: "zero width joiner", + 8206: "left-to-right mark", + 8207: "right-to-left mark", + 8232: "line separator", + 8237: "left-to-right override", + 8238: "right-to-left override", + 8233: "paragraph separator", + 65279: "zero width no-break space", + 65532: "object replacement" +}; +let _supportsTabSize = null; +function supportsTabSize() { + var _a; + if (_supportsTabSize == null && typeof document != "undefined" && document.body) { + let styles = document.body.style; + _supportsTabSize = ((_a = styles.tabSize) !== null && _a !== void 0 ? _a : styles.MozTabSize) != null; + } + return _supportsTabSize || false; } -const BadMouseDetail = browser.ie && browser.ie_version <= 11; -let lastMouseDown = null, lastMouseDownCount = 0, lastMouseDownTime = 0; -function getClickType(event) { - if (!BadMouseDetail) - return event.detail; - let last = lastMouseDown, lastTime = lastMouseDownTime; - lastMouseDown = event; - lastMouseDownTime = Date.now(); - return lastMouseDownCount = !last || (lastTime > Date.now() - 400 && Math.abs(last.clientX - event.clientX) < 2 && - Math.abs(last.clientY - event.clientY) < 2) ? (lastMouseDownCount + 1) % 3 : 1; +const specialCharConfig = state.Facet.define({ + combine(configs) { + let config = state.combineConfig(configs, { + render: null, + specialChars: Specials, + addSpecialChars: null + }); + if (config.replaceTabs = !supportsTabSize()) + config.specialChars = new RegExp("\t|" + config.specialChars.source, UnicodeRegexpSupport); + if (config.addSpecialChars) + config.specialChars = new RegExp(config.specialChars.source + "|" + config.addSpecialChars.source, UnicodeRegexpSupport); + return config; + } +}); +/** +Returns an extension that installs highlighting of special +characters. +*/ +function highlightSpecialChars( +/** +Configuration options. +*/ +config = {}) { + return [specialCharConfig.of(config), specialCharPlugin()]; } -function basicMouseSelection(view, event) { - let start = queryPos(view, event), type = getClickType(event); - let startSel = view.state.selection; - let last = start, lastEvent = event; - return { +let _plugin = null; +function specialCharPlugin() { + return _plugin || (_plugin = ViewPlugin.fromClass(class { + constructor(view) { + this.view = view; + this.decorations = Decoration.none; + this.decorationCache = Object.create(null); + this.decorator = this.makeDecorator(view.state.facet(specialCharConfig)); + this.decorations = this.decorator.createDeco(view); + } + makeDecorator(conf) { + return new MatchDecorator({ + regexp: conf.specialChars, + decoration: (m, view, pos) => { + let { doc } = view.state; + let code = text.codePointAt(m[0], 0); + if (code == 9) { + let line = doc.lineAt(pos); + let size = view.state.tabSize, col = text.countColumn(line.text, size, pos - line.from); + return Decoration.replace({ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth) }); + } + return this.decorationCache[code] || + (this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) })); + }, + boundary: conf.replaceTabs ? undefined : /[^]/ + }); + } update(update) { - if (update.docChanged) { - if (start) - start.pos = update.changes.mapPos(start.pos); - startSel = startSel.map(update.changes); - lastEvent = null; + let conf = update.state.facet(specialCharConfig); + if (update.startState.facet(specialCharConfig) != conf) { + this.decorator = this.makeDecorator(conf); + this.decorations = this.decorator.createDeco(update.view); } - }, - get(event, extend, multiple) { - let cur; - if (lastEvent && event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY) - cur = last; else { - cur = last = queryPos(view, event); - lastEvent = event; - } - if (!cur || !start) - return startSel; - let range = rangeForClick(view, cur.pos, cur.bias, type); - if (start.pos != cur.pos && !extend) { - let startRange = rangeForClick(view, start.pos, start.bias, type); - let from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to); - range = from < range.from ? state.EditorSelection.range(from, to) : state.EditorSelection.range(to, from); + this.decorations = this.decorator.updateDeco(update, this.decorations); } - if (extend) - return startSel.replaceRange(startSel.main.extend(range.from, range.to)); - else if (multiple) - return startSel.addRange(range); - else - return state.EditorSelection.create([range]); } - }; + }, { + decorations: v => v.decorations + })); } -handlers.dragstart = (view, event) => { - let { selection: { main } } = view.state; - let { mouseSelection } = view.inputState; - if (mouseSelection) - mouseSelection.dragging = main; - if (event.dataTransfer) { - event.dataTransfer.setData("Text", view.state.sliceDoc(main.from, main.to)); - event.dataTransfer.effectAllowed = "copyMove"; - } -}; -function dropText(view, event, text, direct) { - if (!text) - return; - let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false); - event.preventDefault(); - let { mouseSelection } = view.inputState; - let del = direct && mouseSelection && mouseSelection.dragging && mouseSelection.dragMove ? - { from: mouseSelection.dragging.from, to: mouseSelection.dragging.to } : null; - let ins = { from: dropPos, insert: text }; - let changes = view.state.changes(del ? [del, ins] : ins); - view.focus(); - view.dispatch({ - changes, - selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) }, - userEvent: del ? "move.drop" : "input.drop" - }); +const DefaultPlaceholder = "\u2022"; +// Assigns placeholder characters from the Control Pictures block to +// ASCII control characters +function placeholder$1(code) { + if (code >= 32) + return DefaultPlaceholder; + if (code == 10) + return "\u2424"; + return String.fromCharCode(9216 + code); } -handlers.drop = (view, event) => { - if (!event.dataTransfer) - return; - if (view.state.readOnly) - return event.preventDefault(); - let files = event.dataTransfer.files; - if (files && files.length) { // For a file drop, read the file's text. - event.preventDefault(); - let text = Array(files.length), read = 0; - let finishFile = () => { - if (++read == files.length) - dropText(view, event, text.filter(s => s != null).join(view.state.lineBreak), false); - }; - for (let i = 0; i < files.length; i++) { - let reader = new FileReader; - reader.onerror = finishFile; - reader.onload = () => { - if (!/[\x00-\x08\x0e-\x1f]{2}/.test(reader.result)) - text[i] = reader.result; - finishFile(); - }; - reader.readAsText(files[i]); - } +class SpecialCharWidget extends WidgetType { + constructor(options, code) { + super(); + this.options = options; + this.code = code; } - else { - dropText(view, event, event.dataTransfer.getData("Text"), true); + eq(other) { return other.code == this.code; } + toDOM(view) { + let ph = placeholder$1(this.code); + let desc = view.state.phrase("Control character") + " " + (Names[this.code] || "0x" + this.code.toString(16)); + let custom = this.options.render && this.options.render(this.code, desc, ph); + if (custom) + return custom; + let span = document.createElement("span"); + span.textContent = ph; + span.title = desc; + span.setAttribute("aria-label", desc); + span.className = "cm-specialChar"; + return span; } -}; -handlers.paste = (view, event) => { - if (view.state.readOnly) - return event.preventDefault(); - view.observer.flush(); - let data = brokenClipboardAPI ? null : event.clipboardData; - if (data) { - doPaste(view, data.getData("text/plain")); - event.preventDefault(); + ignoreEvent() { return false; } +} +class TabWidget extends WidgetType { + constructor(width) { + super(); + this.width = width; } - else { - capturePaste(view); + eq(other) { return other.width == this.width; } + toDOM() { + let span = document.createElement("span"); + span.textContent = "\t"; + span.className = "cm-tab"; + span.style.width = this.width + "px"; + return span; } -}; -function captureCopy(view, text) { - // The extra wrapper is somehow necessary on IE/Edge to prevent the - // content from being mangled when it is put onto the clipboard - let parent = view.dom.parentNode; - if (!parent) - return; - let target = parent.appendChild(document.createElement("textarea")); - target.style.cssText = "position: fixed; left: -10000px; top: 10px"; - target.value = text; - target.focus(); - target.selectionEnd = text.length; - target.selectionStart = 0; - setTimeout(() => { - target.remove(); - view.focus(); - }, 50); + ignoreEvent() { return false; } } -function copiedRange(state) { - let content = [], ranges = [], linewise = false; - for (let range of state.selection.ranges) - if (!range.empty) { - content.push(state.sliceDoc(range.from, range.to)); - ranges.push(range); + +const plugin = ViewPlugin.fromClass(class { + constructor() { + this.height = 1000; + this.attrs = { style: "padding-bottom: 1000px" }; + } + update(update) { + let height = update.view.viewState.editorHeight - update.view.defaultLineHeight; + if (height != this.height) { + this.height = height; + this.attrs = { style: `padding-bottom: ${height}px` }; } - if (!content.length) { - // Nothing selected, do a line-wise copy - let upto = -1; - for (let { from } of state.selection.ranges) { - let line = state.doc.lineAt(from); - if (line.number > upto) { - content.push(line.text); - ranges.push({ from: line.from, to: Math.min(state.doc.length, line.to + 1) }); + } +}); +/** +Returns an extension that makes sure the content has a bottom +margin equivalent to the height of the editor, minus one line +height, so that every line in the document can be scrolled to the +top of the editor. + +This is only meaningful when the editor is scrollable, and should +not be enabled in editors that take the size of their content. +*/ +function scrollPastEnd() { + return [plugin, contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.attrs) || null; })]; +} + +/** +Mark lines that have a cursor on them with the `"cm-activeLine"` +DOM class. +*/ +function highlightActiveLine() { + return activeLineHighlighter; +} +const lineDeco = Decoration.line({ class: "cm-activeLine" }); +const activeLineHighlighter = ViewPlugin.fromClass(class { + constructor(view) { + this.decorations = this.getDeco(view); + } + update(update) { + if (update.docChanged || update.selectionSet) + this.decorations = this.getDeco(update.view); + } + getDeco(view) { + let lastLineStart = -1, deco = []; + for (let r of view.state.selection.ranges) { + if (!r.empty) + return Decoration.none; + let line = view.lineBlockAt(r.head); + if (line.from > lastLineStart) { + deco.push(lineDeco.range(line.from)); + lastLineStart = line.from; } - upto = line.number; } - linewise = true; + return Decoration.set(deco); } - return { text: content.join(state.lineBreak), ranges, linewise }; -} -let lastLinewiseCopy = null; -handlers.copy = handlers.cut = (view, event) => { - let { text, ranges, linewise } = copiedRange(view.state); - if (!text && !linewise) - return; - lastLinewiseCopy = linewise ? text : null; - let data = brokenClipboardAPI ? null : event.clipboardData; - if (data) { - event.preventDefault(); - data.clearData(); - data.setData("text/plain", text); +}, { + decorations: v => v.decorations +}); + +class Placeholder extends WidgetType { + constructor(content) { + super(); + this.content = content; } - else { - captureCopy(view, text); + toDOM() { + let wrap = document.createElement("span"); + wrap.className = "cm-placeholder"; + wrap.style.pointerEvents = "none"; + wrap.appendChild(typeof this.content == "string" ? document.createTextNode(this.content) : this.content); + if (typeof this.content == "string") + wrap.setAttribute("aria-label", "placeholder " + this.content); + else + wrap.setAttribute("aria-hidden", "true"); + return wrap; } - if (event.type == "cut" && !view.state.readOnly) - view.dispatch({ - changes: ranges, - scrollIntoView: true, - userEvent: "delete.cut" + ignoreEvent() { return false; } +} +/** +Extension that enables a placeholder—a piece of example content +to show when the editor is empty. +*/ +function placeholder(content) { + return ViewPlugin.fromClass(class { + constructor(view) { + this.view = view; + this.placeholder = Decoration.set([Decoration.widget({ widget: new Placeholder(content), side: 1 }).range(0)]); + } + get decorations() { return this.view.state.doc.length ? Decoration.none : this.placeholder; } + }, { decorations: v => v.decorations }); +} + +/** +@internal +*/ +const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually }; + +Object.defineProperty(exports, 'Range', { + enumerable: true, + get: function () { return rangeset.Range; } +}); +exports.BidiSpan = BidiSpan; +exports.BlockInfo = BlockInfo; +exports.Decoration = Decoration; +exports.EditorView = EditorView; +exports.MatchDecorator = MatchDecorator; +exports.PluginField = PluginField; +exports.PluginFieldProvider = PluginFieldProvider; +exports.ViewPlugin = ViewPlugin; +exports.ViewUpdate = ViewUpdate; +exports.WidgetType = WidgetType; +exports.__test = __test; +exports.drawSelection = drawSelection; +exports.dropCursor = dropCursor; +exports.highlightActiveLine = highlightActiveLine; +exports.highlightSpecialChars = highlightSpecialChars; +exports.keymap = keymap; +exports.logException = logException; +exports.placeholder = placeholder; +exports.runScopeHandlers = runScopeHandlers; +exports.scrollPastEnd = scrollPastEnd; + +},{"@codemirror/rangeset":29,"@codemirror/state":30,"@codemirror/text":31,"style-mod":129,"w3c-keyname":130}],34:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +// FIXME profile adding a per-Tree TreeNode cache, validating it by +// parent pointer +/// The default maximum length of a `TreeBuffer` node (1024). +const DefaultBufferLength = 1024; +let nextPropID = 0; +class Range { + constructor(from, to) { + this.from = from; + this.to = to; + } +} +/// Each [node type](#common.NodeType) or [individual tree](#common.Tree) +/// can have metadata associated with it in props. Instances of this +/// class represent prop names. +class NodeProp { + /// Create a new node prop type. + constructor(config = {}) { + this.id = nextPropID++; + this.perNode = !!config.perNode; + this.deserialize = config.deserialize || (() => { + throw new Error("This node type doesn't define a deserialize function"); }); -}; -handlers.focus = handlers.blur = view => { - setTimeout(() => { - if (view.hasFocus != view.inputState.notifiedFocused) - view.update([]); - }, 10); -}; -handlers.beforeprint = view => { - view.viewState.printing = true; - view.requestMeasure(); - setTimeout(() => { - view.viewState.printing = false; - view.requestMeasure(); - }, 2000); -}; -function forceClearComposition(view, rapid) { - if (view.docView.compositionDeco.size) { - view.inputState.rapidCompositionStart = rapid; - try { - view.update([]); + } + /// This is meant to be used with + /// [`NodeSet.extend`](#common.NodeSet.extend) or + /// [`LRParser.configure`](#lr.ParserConfig.props) to compute + /// prop values for each node type in the set. Takes a [match + /// object](#common.NodeType^match) or function that returns undefined + /// if the node type doesn't get this prop, and the prop's value if + /// it does. + add(match) { + if (this.perNode) + throw new RangeError("Can't add per-node props to node types"); + if (typeof match != "function") + match = NodeType.match(match); + return (type) => { + let result = match(type); + return result === undefined ? null : [this, result]; + }; + } +} +/// Prop that is used to describe matching delimiters. For opening +/// delimiters, this holds an array of node names (written as a +/// space-separated string when declaring this prop in a grammar) +/// for the node types of closing delimiters that match it. +NodeProp.closedBy = new NodeProp({ deserialize: str => str.split(" ") }); +/// The inverse of [`closedBy`](#common.NodeProp^closedBy). This is +/// attached to closing delimiters, holding an array of node names +/// of types of matching opening delimiters. +NodeProp.openedBy = new NodeProp({ deserialize: str => str.split(" ") }); +/// Used to assign node types to groups (for example, all node +/// types that represent an expression could be tagged with an +/// `"Expression"` group). +NodeProp.group = new NodeProp({ deserialize: str => str.split(" ") }); +/// The hash of the [context](#lr.ContextTracker.constructor) +/// that the node was parsed in, if any. Used to limit reuse of +/// contextual nodes. +NodeProp.contextHash = new NodeProp({ perNode: true }); +/// The distance beyond the end of the node that the tokenizer +/// looked ahead for any of the tokens inside the node. (The LR +/// parser only stores this when it is larger than 25, for +/// efficiency reasons.) +NodeProp.lookAhead = new NodeProp({ perNode: true }); +/// This per-node prop is used to replace a given node, or part of a +/// node, with another tree. This is useful to include trees from +/// different languages. +NodeProp.mounted = new NodeProp({ perNode: true }); +/// A mounted tree, which can be [stored](#common.NodeProp^mounted) on +/// a tree node to indicate that parts of its content are +/// represented by another tree. +class MountedTree { + constructor( + /// The inner tree. + tree, + /// If this is null, this tree replaces the entire node (it will + /// be included in the regular iteration instead of its host + /// node). If not, only the given ranges are considered to be + /// covered by this tree. This is used for trees that are mixed in + /// a way that isn't strictly hierarchical. Such mounted trees are + /// only entered by [`resolveInner`](#common.Tree.resolveInner) + /// and [`enter`](#common.SyntaxNode.enter). + overlay, + /// The parser used to create this subtree. + parser) { + this.tree = tree; + this.overlay = overlay; + this.parser = parser; + } +} +const noProps = Object.create(null); +/// Each node in a syntax tree has a node type associated with it. +class NodeType { + /// @internal + constructor( + /// The name of the node type. Not necessarily unique, but if the + /// grammar was written properly, different node types with the + /// same name within a node set should play the same semantic + /// role. + name, + /// @internal + props, + /// The id of this node in its set. Corresponds to the term ids + /// used in the parser. + id, + /// @internal + flags = 0) { + this.name = name; + this.props = props; + this.id = id; + this.flags = flags; + } + static define(spec) { + let props = spec.props && spec.props.length ? Object.create(null) : noProps; + let flags = (spec.top ? 1 /* Top */ : 0) | (spec.skipped ? 2 /* Skipped */ : 0) | + (spec.error ? 4 /* Error */ : 0) | (spec.name == null ? 8 /* Anonymous */ : 0); + let type = new NodeType(spec.name || "", props, spec.id, flags); + if (spec.props) + for (let src of spec.props) { + if (!Array.isArray(src)) + src = src(type); + if (src) { + if (src[0].perNode) + throw new RangeError("Can't store a per-node prop on a node type"); + props[src[0].id] = src[1]; + } + } + return type; + } + /// Retrieves a node prop for this type. Will return `undefined` if + /// the prop isn't present on this node. + prop(prop) { return this.props[prop.id]; } + /// True when this is the top node of a grammar. + get isTop() { return (this.flags & 1 /* Top */) > 0; } + /// True when this node is produced by a skip rule. + get isSkipped() { return (this.flags & 2 /* Skipped */) > 0; } + /// Indicates whether this is an error node. + get isError() { return (this.flags & 4 /* Error */) > 0; } + /// When true, this node type doesn't correspond to a user-declared + /// named node, for example because it is used to cache repetition. + get isAnonymous() { return (this.flags & 8 /* Anonymous */) > 0; } + /// Returns true when this node's name or one of its + /// [groups](#common.NodeProp^group) matches the given string. + is(name) { + if (typeof name == 'string') { + if (this.name == name) + return true; + let group = this.prop(NodeProp.group); + return group ? group.indexOf(name) > -1 : false; } - finally { - view.inputState.rapidCompositionStart = false; + return this.id == name; + } + /// Create a function from node types to arbitrary values by + /// specifying an object whose property names are node or + /// [group](#common.NodeProp^group) names. Often useful with + /// [`NodeProp.add`](#common.NodeProp.add). You can put multiple + /// names, separated by spaces, in a single property name to map + /// multiple node names to a single value. + static match(map) { + let direct = Object.create(null); + for (let prop in map) + for (let name of prop.split(" ")) + direct[name] = map[prop]; + return (node) => { + for (let groups = node.prop(NodeProp.group), i = -1; i < (groups ? groups.length : 0); i++) { + let found = direct[i < 0 ? node.name : groups[i]]; + if (found) + return found; + } + }; + } +} +/// An empty dummy node type to use when no actual type is available. +NodeType.none = new NodeType("", Object.create(null), 0, 8 /* Anonymous */); +/// A node set holds a collection of node types. It is used to +/// compactly represent trees by storing their type ids, rather than a +/// full pointer to the type object, in a numeric array. Each parser +/// [has](#lr.LRParser.nodeSet) a node set, and [tree +/// buffers](#common.TreeBuffer) can only store collections of nodes +/// from the same set. A set can have a maximum of 2**16 (65536) node +/// types in it, so that the ids fit into 16-bit typed array slots. +class NodeSet { + /// Create a set with the given types. The `id` property of each + /// type should correspond to its position within the array. + constructor( + /// The node types in this set, by id. + types) { + this.types = types; + for (let i = 0; i < types.length; i++) + if (types[i].id != i) + throw new RangeError("Node type ids should correspond to array positions when creating a node set"); + } + /// Create a copy of this set with some node properties added. The + /// arguments to this method should be created with + /// [`NodeProp.add`](#common.NodeProp.add). + extend(...props) { + let newTypes = []; + for (let type of this.types) { + let newProps = null; + for (let source of props) { + let add = source(type); + if (add) { + if (!newProps) + newProps = Object.assign({}, type.props); + newProps[add[0].id] = add[1]; + } + } + newTypes.push(newProps ? new NodeType(type.name, newProps, type.id, type.flags) : type); } + return new NodeSet(newTypes); } } -handlers.compositionstart = handlers.compositionupdate = view => { - if (view.inputState.compositionFirstChange == null) - view.inputState.compositionFirstChange = true; - if (view.inputState.composing < 0) { - // FIXME possibly set a timeout to clear it again on Android - view.inputState.composing = 0; - if (view.docView.compositionDeco.size) { - view.observer.flush(); - forceClearComposition(view, true); +const CachedNode = new WeakMap(), CachedInnerNode = new WeakMap(); +/// A piece of syntax tree. There are two ways to approach these +/// trees: the way they are actually stored in memory, and the +/// convenient way. +/// +/// Syntax trees are stored as a tree of `Tree` and `TreeBuffer` +/// objects. By packing detail information into `TreeBuffer` leaf +/// nodes, the representation is made a lot more memory-efficient. +/// +/// However, when you want to actually work with tree nodes, this +/// representation is very awkward, so most client code will want to +/// use the [`TreeCursor`](#common.TreeCursor) or +/// [`SyntaxNode`](#common.SyntaxNode) interface instead, which provides +/// a view on some part of this data structure, and can be used to +/// move around to adjacent nodes. +class Tree { + /// Construct a new tree. See also [`Tree.build`](#common.Tree^build). + constructor( + /// The type of the top node. + type, + /// This node's child nodes. + children, + /// The positions (offsets relative to the start of this tree) of + /// the children. + positions, + /// The total length of this tree + length, + /// Per-node [node props](#common.NodeProp) to associate with this node. + props) { + this.type = type; + this.children = children; + this.positions = positions; + this.length = length; + /// @internal + this.props = null; + if (props && props.length) { + this.props = Object.create(null); + for (let [prop, value] of props) + this.props[typeof prop == "number" ? prop : prop.id] = value; } } -}; -handlers.compositionend = view => { - view.inputState.composing = -1; - view.inputState.compositionEndedAt = Date.now(); - view.inputState.compositionFirstChange = null; - setTimeout(() => { - if (view.inputState.composing < 0) - forceClearComposition(view, false); - }, 50); -}; -handlers.contextmenu = view => { - view.inputState.lastContextMenu = Date.now(); -}; -handlers.beforeinput = (view, event) => { - var _a; - // Because Chrome Android doesn't fire useful key events, use - // beforeinput to detect backspace (and possibly enter and delete, - // but those usually don't even seem to fire beforeinput events at - // the moment) and fake a key event for it. - // - // (preventDefault on beforeinput, though supported in the spec, - // seems to do nothing at all on Chrome). - let pending; - if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) { - view.observer.delayAndroidKey(pending.key, pending.keyCode); - if (pending.key == "Backspace" || pending.key == "Delete") { - let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0; - setTimeout(() => { - var _a; - // Backspacing near uneditable nodes on Chrome Android sometimes - // closes the virtual keyboard. This tries to crudely detect - // that and refocus to get it back. - if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) { - view.contentDOM.blur(); - view.focus(); - } - }, 100); + /// @internal + toString() { + let mounted = this.prop(NodeProp.mounted); + if (mounted && !mounted.overlay) + return mounted.tree.toString(); + let children = ""; + for (let ch of this.children) { + let str = ch.toString(); + if (str) { + if (children) + children += ","; + children += str; + } } + return !this.type.name ? children : + (/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) + + (children.length ? "(" + children + ")" : ""); } -}; - -const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"]; -class HeightOracle { - constructor() { - this.doc = text.Text.empty; - this.lineWrapping = false; - this.direction = exports.Direction.LTR; - this.heightSamples = {}; - this.lineHeight = 14; - this.charWidth = 7; - this.lineLength = 30; - // Used to track, during updateHeight, if any actual heights changed - this.heightChanged = false; + /// Get a [tree cursor](#common.TreeCursor) rooted at this tree. When + /// `pos` is given, the cursor is [moved](#common.TreeCursor.moveTo) + /// to the given position and side. + cursor(pos, side = 0) { + let scope = (pos != null && CachedNode.get(this)) || this.topNode; + let cursor = new TreeCursor(scope); + if (pos != null) { + cursor.moveTo(pos, side); + CachedNode.set(this, cursor._tree); + } + return cursor; } - heightForGap(from, to) { - let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1; - if (this.lineWrapping) - lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength); - return this.lineHeight * lines; + /// Get a [tree cursor](#common.TreeCursor) that, unlike regular + /// cursors, doesn't skip through + /// [anonymous](#common.NodeType.isAnonymous) nodes and doesn't + /// automatically enter mounted nodes. + fullCursor() { + return new TreeCursor(this.topNode, 1 /* Full */); } - heightForLine(length) { - if (!this.lineWrapping) - return this.lineHeight; - let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / (this.lineLength - 5))); - return lines * this.lineHeight; + /// Get a [syntax node](#common.SyntaxNode) object for the top of the + /// tree. + get topNode() { + return new TreeNode(this, 0, 0, null); } - setDoc(doc) { this.doc = doc; return this; } - mustRefreshForStyle(whiteSpace, direction) { - return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction; + /// Get the [syntax node](#common.SyntaxNode) at the given position. + /// If `side` is -1, this will move into nodes that end at the + /// position. If 1, it'll move into nodes that start at the + /// position. With 0, it'll only enter nodes that cover the position + /// from both sides. + resolve(pos, side = 0) { + let node = resolveNode(CachedNode.get(this) || this.topNode, pos, side, false); + CachedNode.set(this, node); + return node; } - mustRefreshForHeights(lineHeights) { - let newHeight = false; - for (let i = 0; i < lineHeights.length; i++) { - let h = lineHeights[i]; - if (h < 0) { - i++; + /// Like [`resolve`](#common.Tree.resolve), but will enter + /// [overlaid](#common.MountedTree.overlay) nodes, producing a syntax node + /// pointing into the innermost overlaid tree at the given position + /// (with parent links going through all parent structure, including + /// the host trees). + resolveInner(pos, side = 0) { + let node = resolveNode(CachedInnerNode.get(this) || this.topNode, pos, side, true); + CachedInnerNode.set(this, node); + return node; + } + /// Iterate over the tree and its children, calling `enter` for any + /// node that touches the `from`/`to` region (if given) before + /// running over such a node's children, and `leave` (if given) when + /// leaving the node. When `enter` returns `false`, that node will + /// not have its children iterated over (or `leave` called). + iterate(spec) { + let { enter, leave, from = 0, to = this.length } = spec; + for (let c = this.cursor(), get = () => c.node;;) { + let mustLeave = false; + if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c.type, c.from, c.to, get) !== false)) { + if (c.firstChild()) + continue; + if (!c.type.isAnonymous) + mustLeave = true; } - else if (!this.heightSamples[Math.floor(h * 10)]) { // Round to .1 pixels - newHeight = true; - this.heightSamples[Math.floor(h * 10)] = true; + for (;;) { + if (mustLeave && leave) + leave(c.type, c.from, c.to, get); + mustLeave = c.type.isAnonymous; + if (c.nextSibling()) + break; + if (!c.parent()) + return; + mustLeave = true; } } - return newHeight; } - refresh(whiteSpace, direction, lineHeight, charWidth, lineLength, knownHeights) { - let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1; - let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || - this.lineWrapping != lineWrapping || - this.direction != direction; - this.lineWrapping = lineWrapping; - this.direction = direction; - this.lineHeight = lineHeight; - this.charWidth = charWidth; - this.lineLength = lineLength; - if (changed) { - this.heightSamples = {}; - for (let i = 0; i < knownHeights.length; i++) { - let h = knownHeights[i]; - if (h < 0) - i++; - else - this.heightSamples[Math.floor(h * 10)] = true; - } - } - return changed; + /// Get the value of the given [node prop](#common.NodeProp) for this + /// node. Works with both per-node and per-type props. + prop(prop) { + return !prop.perNode ? this.type.prop(prop) : this.props ? this.props[prop.id] : undefined; } + /// Returns the node's [per-node props](#common.NodeProp.perNode) in a + /// format that can be passed to the [`Tree`](#common.Tree) + /// constructor. + get propValues() { + let result = []; + if (this.props) + for (let id in this.props) + result.push([+id, this.props[id]]); + return result; + } + /// Balance the direct children of this tree, producing a copy of + /// which may have children grouped into subtrees with type + /// [`NodeType.none`](#common.NodeType^none). + balance(config = {}) { + return this.children.length <= 8 /* BranchFactor */ ? this : + balanceRange(NodeType.none, this.children, this.positions, 0, this.children.length, 0, this.length, (children, positions, length) => new Tree(this.type, children, positions, length, this.propValues), config.makeTree || ((children, positions, length) => new Tree(NodeType.none, children, positions, length))); + } + /// Build a tree from a postfix-ordered buffer of node information, + /// or a cursor over such a buffer. + static build(data) { return buildTree(data); } } -// This object is used by `updateHeight` to make DOM measurements -// arrive at the right nides. The `heights` array is a sequence of -// block heights, starting from position `from`. -class MeasuredHeights { - constructor(from, heights) { - this.from = from; - this.heights = heights; - this.index = 0; +/// The empty tree +Tree.empty = new Tree(NodeType.none, [], [], 0); +class FlatBufferCursor { + constructor(buffer, index) { + this.buffer = buffer; + this.index = index; } - get more() { return this.index < this.heights.length; } + get id() { return this.buffer[this.index - 4]; } + get start() { return this.buffer[this.index - 3]; } + get end() { return this.buffer[this.index - 2]; } + get size() { return this.buffer[this.index - 1]; } + get pos() { return this.index; } + next() { this.index -= 4; } + fork() { return new FlatBufferCursor(this.buffer, this.index); } } -/** -Record used to represent information about a block-level element -in the editor view. -*/ -class BlockInfo { - /** - @internal - */ +/// Tree buffers contain (type, start, end, endIndex) quads for each +/// node. In such a buffer, nodes are stored in prefix order (parents +/// before children, with the endIndex of the parent indicating which +/// children belong to it) +class TreeBuffer { + /// Create a tree buffer. constructor( - /** - The start of the element in the document. - */ - from, - /** - The length of the element. - */ + /// The buffer's content. + buffer, + /// The total length of the group of nodes in the buffer. length, - /** - The top position of the element (relative to the top of the - document). - */ - top, - /** - Its height. - */ - height, - /** - The type of element this is. When querying lines, this may be - an array of all the blocks that make up the line. - */ - type) { - this.from = from; + /// The node set used in this buffer. + set) { + this.buffer = buffer; this.length = length; - this.top = top; - this.height = height; - this.type = type; + this.set = set; } - /** - The end of the element as a document position. - */ - get to() { return this.from + this.length; } - /** - The bottom position of the element. - */ - get bottom() { return this.top + this.height; } - /** - @internal - */ - join(other) { - let detail = (Array.isArray(this.type) ? this.type : [this]) - .concat(Array.isArray(other.type) ? other.type : [other]); - return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail); + /// @internal + get type() { return NodeType.none; } + /// @internal + toString() { + let result = []; + for (let index = 0; index < this.buffer.length;) { + result.push(this.childString(index)); + index = this.buffer[index + 3]; + } + return result.join(","); } - /** - FIXME remove on next breaking release @internal - */ - moveY(offset) { - return !offset ? this : new BlockInfo(this.from, this.length, this.top + offset, this.height, Array.isArray(this.type) ? this.type.map(b => b.moveY(offset)) : this.type); + /// @internal + childString(index) { + let id = this.buffer[index], endIndex = this.buffer[index + 3]; + let type = this.set.types[id], result = type.name; + if (/\W/.test(result) && !type.isError) + result = JSON.stringify(result); + index += 4; + if (endIndex == index) + return result; + let children = []; + while (index < endIndex) { + children.push(this.childString(index)); + index = this.buffer[index + 3]; + } + return result + "(" + children.join(",") + ")"; + } + /// @internal + findChild(startIndex, endIndex, dir, pos, side) { + let { buffer } = this, pick = -1; + for (let i = startIndex; i != endIndex; i = buffer[i + 3]) { + if (checkSide(side, pos, buffer[i + 1], buffer[i + 2])) { + pick = i; + if (dir > 0) + break; + } + } + return pick; + } + /// @internal + slice(startI, endI, from, to) { + let b = this.buffer; + let copy = new Uint16Array(endI - startI); + for (let i = startI, j = 0; i < endI;) { + copy[j++] = b[i++]; + copy[j++] = b[i++] - from; + copy[j++] = b[i++] - from; + copy[j++] = b[i++] - startI; + } + return new TreeBuffer(copy, to - from, this.set); } } -var QueryType; -(function (QueryType) { - QueryType[QueryType["ByPos"] = 0] = "ByPos"; - QueryType[QueryType["ByHeight"] = 1] = "ByHeight"; - QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight"; -})(QueryType || (QueryType = {})); -const Epsilon = 1e-3; -class HeightMap { - constructor(length, // The number of characters covered - height, // Height of this part of the document - flags = 2 /* Outdated */) { - this.length = length; - this.height = height; - this.flags = flags; +function checkSide(side, pos, from, to) { + switch (side) { + case -2 /* Before */: return from < pos; + case -1 /* AtOrBefore */: return to >= pos && from < pos; + case 0 /* Around */: return from < pos && to > pos; + case 1 /* AtOrAfter */: return from <= pos && to > pos; + case 2 /* After */: return to > pos; + case 4 /* DontCare */: return true; } - get outdated() { return (this.flags & 2 /* Outdated */) > 0; } - set outdated(value) { this.flags = (value ? 2 /* Outdated */ : 0) | (this.flags & ~2 /* Outdated */); } - setHeight(oracle, height) { - if (this.height != height) { - if (Math.abs(this.height - height) > Epsilon) - oracle.heightChanged = true; - this.height = height; +} +function enterUnfinishedNodesBefore(node, pos) { + let scan = node.childBefore(pos); + while (scan) { + let last = scan.lastChild; + if (!last || last.to != scan.to) + break; + if (last.type.isError && last.from == last.to) { + node = scan; + scan = last.prevSibling; + } + else { + scan = last; } } - // Base case is to replace a leaf node, which simply builds a tree - // from the new nodes and returns that (HeightMapBranch and - // HeightMapGap override this to actually use from/to) - replace(_from, _to, nodes) { - return HeightMap.of(nodes); + return node; +} +function resolveNode(node, pos, side, overlays) { + var _a; + // Move up to a node that actually holds the position, if possible + while (node.from == node.to || + (side < 1 ? node.from >= pos : node.from > pos) || + (side > -1 ? node.to <= pos : node.to < pos)) { + let parent = !overlays && node instanceof TreeNode && node.index < 0 ? null : node.parent; + if (!parent) + return node; + node = parent; } - // Again, these are base cases, and are overridden for branch and gap nodes. - decomposeLeft(_to, result) { result.push(this); } - decomposeRight(_from, result) { result.push(this); } - applyChanges(decorations, oldDoc, oracle, changes) { - let me = this; - for (let i = changes.length - 1; i >= 0; i--) { - let { fromA, toA, fromB, toB } = changes[i]; - let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0); - let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oldDoc, 0, 0); - toB += end.to - toA; - toA = end.to; - while (i > 0 && start.from <= changes[i - 1].toA) { - fromA = changes[i - 1].fromA; - fromB = changes[i - 1].fromB; - i--; - if (fromA < start.from) - start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0); - } - fromB += start.from - fromA; - fromA = start.from; - let nodes = NodeBuilder.build(oracle, decorations, fromB, toB); - me = me.replace(fromA, toA, nodes); + // Must go up out of overlays when those do not overlap with pos + if (overlays) + for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) { + if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side, true)) === null || _a === void 0 ? void 0 : _a.from) != scan.from) + node = parent; } - return me.updateHeight(oracle, 0); + for (;;) { + let inner = node.enter(pos, side, overlays); + if (!inner) + return node; + node = inner; + } +} +class TreeNode { + constructor(node, _from, + // Index in parent node, set to -1 if the node is not a direct child of _parent.node (overlay) + index, _parent) { + this.node = node; + this._from = _from; + this.index = index; + this._parent = _parent; } - static empty() { return new HeightMapText(0, 0); } - // nodes uses null values to indicate the position of line breaks. - // There are never line breaks at the start or end of the array, or - // two line breaks next to each other, and the array isn't allowed - // to be empty (same restrictions as return value from the builder). - static of(nodes) { - if (nodes.length == 1) - return nodes[0]; - let i = 0, j = nodes.length, before = 0, after = 0; - for (;;) { - if (i == j) { - if (before > after * 2) { - let split = nodes[i - 1]; - if (split.break) - nodes.splice(--i, 1, split.left, null, split.right); - else - nodes.splice(--i, 1, split.left, split.right); - j += 1 + split.break; - before -= split.size; - } - else if (after > before * 2) { - let split = nodes[j]; - if (split.break) - nodes.splice(j, 1, split.left, null, split.right); - else - nodes.splice(j, 1, split.left, split.right); - j += 2 + split.break; - after -= split.size; + get type() { return this.node.type; } + get name() { return this.node.type.name; } + get from() { return this._from; } + get to() { return this._from + this.node.length; } + nextChild(i, dir, pos, side, mode = 0) { + for (let parent = this;;) { + for (let { children, positions } = parent.node, e = dir > 0 ? children.length : -1; i != e; i += dir) { + let next = children[i], start = positions[i] + parent._from; + if (!checkSide(side, pos, start, start + next.length)) + continue; + if (next instanceof TreeBuffer) { + if (mode & 2 /* NoEnterBuffer */) + continue; + let index = next.findChild(0, next.buffer.length, dir, pos - start, side); + if (index > -1) + return new BufferNode(new BufferContext(parent, next, i, start), null, index); } - else { - break; + else if ((mode & 1 /* Full */) || (!next.type.isAnonymous || hasChild(next))) { + let mounted; + if (!(mode & 1 /* Full */) && next.props && (mounted = next.prop(NodeProp.mounted)) && !mounted.overlay) + return new TreeNode(mounted.tree, start, i, parent); + let inner = new TreeNode(next, start, i, parent); + return (mode & 1 /* Full */) || !inner.type.isAnonymous ? inner + : inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side); } } - else if (before < after) { - let next = nodes[i++]; - if (next) - before += next.size; - } - else { - let next = nodes[--j]; - if (next) - after += next.size; - } - } - let brk = 0; - if (nodes[i - 1] == null) { - brk = 1; - i--; + if ((mode & 1 /* Full */) || !parent.type.isAnonymous) + return null; + if (parent.index >= 0) + i = parent.index + dir; + else + i = dir < 0 ? -1 : parent._parent.node.children.length; + parent = parent._parent; + if (!parent) + return null; } - else if (nodes[i] == null) { - brk = 1; - j++; + } + get firstChild() { return this.nextChild(0, 1, 0, 4 /* DontCare */); } + get lastChild() { return this.nextChild(this.node.children.length - 1, -1, 0, 4 /* DontCare */); } + childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* After */); } + childBefore(pos) { return this.nextChild(this.node.children.length - 1, -1, pos, -2 /* Before */); } + enter(pos, side, overlays = true, buffers = true) { + let mounted; + if (overlays && (mounted = this.node.prop(NodeProp.mounted)) && mounted.overlay) { + let rPos = pos - this.from; + for (let { from, to } of mounted.overlay) { + if ((side > 0 ? from <= rPos : from < rPos) && + (side < 0 ? to >= rPos : to > rPos)) + return new TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this); + } } - return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j))); + return this.nextChild(0, 1, pos, side, buffers ? 0 : 2 /* NoEnterBuffer */); } -} -HeightMap.prototype.size = 1; -class HeightMapBlock extends HeightMap { - constructor(length, height, type) { - super(length, height); - this.type = type; + nextSignificantParent() { + let val = this; + while (val.type.isAnonymous && val._parent) + val = val._parent; + return val; } - blockAt(_height, _doc, top, offset) { - return new BlockInfo(offset, this.length, top, this.height, this.type); + get parent() { + return this._parent ? this._parent.nextSignificantParent() : null; } - lineAt(_value, _type, doc, top, offset) { - return this.blockAt(0, doc, top, offset); + get nextSibling() { + return this._parent && this.index >= 0 ? this._parent.nextChild(this.index + 1, 1, 0, 4 /* DontCare */) : null; } - forEachLine(_from, _to, doc, top, offset, f) { - f(this.blockAt(0, doc, top, offset)); + get prevSibling() { + return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* DontCare */) : null; } - updateHeight(oracle, offset = 0, _force = false, measured) { - if (measured && measured.from <= offset && measured.more) - this.setHeight(oracle, measured.heights[measured.index++]); - this.outdated = false; - return this; + get cursor() { return new TreeCursor(this); } + get tree() { return this.node; } + toTree() { return this.node; } + resolve(pos, side = 0) { + return resolveNode(this, pos, side, false); } - toString() { return `block(${this.length})`; } -} -class HeightMapText extends HeightMapBlock { - constructor(length, height) { - super(length, height, exports.BlockType.Text); - this.collapsed = 0; // Amount of collapsed content in the line - this.widgetHeight = 0; // Maximum inline widget height + resolveInner(pos, side = 0) { + return resolveNode(this, pos, side, true); } - replace(_from, _to, nodes) { - let node = nodes[0]; - if (nodes.length == 1 && (node instanceof HeightMapText || node instanceof HeightMapGap && (node.flags & 4 /* SingleLine */)) && - Math.abs(this.length - node.length) < 10) { - if (node instanceof HeightMapGap) - node = new HeightMapText(node.length, this.height); - else - node.height = this.height; - if (!this.outdated) - node.outdated = false; - return node; - } - else { - return HeightMap.of(nodes); - } + enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); } + getChild(type, before = null, after = null) { + let r = getChildren(this, type, before, after); + return r.length ? r[0] : null; } - updateHeight(oracle, offset = 0, force = false, measured) { - if (measured && measured.from <= offset && measured.more) - this.setHeight(oracle, measured.heights[measured.index++]); - else if (force || this.outdated) - this.setHeight(oracle, Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed))); - this.outdated = false; - return this; + getChildren(type, before = null, after = null) { + return getChildren(this, type, before, after); } - toString() { - return `line(${this.length}${this.collapsed ? -this.collapsed : ""}${this.widgetHeight ? ":" + this.widgetHeight : ""})`; + /// @internal + toString() { return this.node.toString(); } +} +function getChildren(node, type, before, after) { + let cur = node.cursor, result = []; + if (!cur.firstChild()) + return result; + if (before != null) + while (!cur.type.is(before)) + if (!cur.nextSibling()) + return result; + for (;;) { + if (after != null && cur.type.is(after)) + return result; + if (cur.type.is(type)) + result.push(cur.node); + if (!cur.nextSibling()) + return after == null ? result : []; } } -class HeightMapGap extends HeightMap { - constructor(length) { super(length, 0); } - lines(doc, offset) { - let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number; - return { firstLine, lastLine, lineHeight: this.height / (lastLine - firstLine + 1) }; +class BufferContext { + constructor(parent, buffer, index, start) { + this.parent = parent; + this.buffer = buffer; + this.index = index; + this.start = start; } - blockAt(height, doc, top, offset) { - let { firstLine, lastLine, lineHeight } = this.lines(doc, offset); - let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / lineHeight))); - let { from, length } = doc.line(firstLine + line); - return new BlockInfo(from, length, top + lineHeight * line, lineHeight, exports.BlockType.Text); +} +class BufferNode { + constructor(context, _parent, index) { + this.context = context; + this._parent = _parent; + this.index = index; + this.type = context.buffer.set.types[context.buffer.buffer[index]]; } - lineAt(value, type, doc, top, offset) { - if (type == QueryType.ByHeight) - return this.blockAt(value, doc, top, offset); - if (type == QueryType.ByPosNoHeight) { - let { from, to } = doc.lineAt(value); - return new BlockInfo(from, to - from, 0, 0, exports.BlockType.Text); - } - let { firstLine, lineHeight } = this.lines(doc, offset); - let { from, length, number } = doc.lineAt(value); - return new BlockInfo(from, length, top + lineHeight * (number - firstLine), lineHeight, exports.BlockType.Text); + get name() { return this.type.name; } + get from() { return this.context.start + this.context.buffer.buffer[this.index + 1]; } + get to() { return this.context.start + this.context.buffer.buffer[this.index + 2]; } + child(dir, pos, side) { + let { buffer } = this.context; + let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.context.start, side); + return index < 0 ? null : new BufferNode(this.context, this, index); } - forEachLine(from, to, doc, top, offset, f) { - let { firstLine, lineHeight } = this.lines(doc, offset); - for (let pos = Math.max(from, offset), end = Math.min(offset + this.length, to); pos <= end;) { - let line = doc.lineAt(pos); - if (pos == from) - top += lineHeight * (line.number - firstLine); - f(new BlockInfo(line.from, line.length, top, lineHeight, exports.BlockType.Text)); - top += lineHeight; - pos = line.to + 1; + get firstChild() { return this.child(1, 0, 4 /* DontCare */); } + get lastChild() { return this.child(-1, 0, 4 /* DontCare */); } + childAfter(pos) { return this.child(1, pos, 2 /* After */); } + childBefore(pos) { return this.child(-1, pos, -2 /* Before */); } + enter(pos, side, overlays, buffers = true) { + if (!buffers) + return null; + let { buffer } = this.context; + let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side); + return index < 0 ? null : new BufferNode(this.context, this, index); + } + get parent() { + return this._parent || this.context.parent.nextSignificantParent(); + } + externalSibling(dir) { + return this._parent ? null : this.context.parent.nextChild(this.context.index + dir, dir, 0, 4 /* DontCare */); + } + get nextSibling() { + let { buffer } = this.context; + let after = buffer.buffer[this.index + 3]; + if (after < (this._parent ? buffer.buffer[this._parent.index + 3] : buffer.buffer.length)) + return new BufferNode(this.context, this._parent, after); + return this.externalSibling(1); + } + get prevSibling() { + let { buffer } = this.context; + let parentStart = this._parent ? this._parent.index + 4 : 0; + if (this.index == parentStart) + return this.externalSibling(-1); + return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */)); + } + get cursor() { return new TreeCursor(this); } + get tree() { return null; } + toTree() { + let children = [], positions = []; + let { buffer } = this.context; + let startI = this.index + 4, endI = buffer.buffer[this.index + 3]; + if (endI > startI) { + let from = buffer.buffer[this.index + 1], to = buffer.buffer[this.index + 2]; + children.push(buffer.slice(startI, endI, from, to)); + positions.push(0); } + return new Tree(this.type, children, positions, this.to - this.from); } - replace(from, to, nodes) { - let after = this.length - to; - if (after > 0) { - let last = nodes[nodes.length - 1]; - if (last instanceof HeightMapGap) - nodes[nodes.length - 1] = new HeightMapGap(last.length + after); - else - nodes.push(null, new HeightMapGap(after - 1)); + resolve(pos, side = 0) { + return resolveNode(this, pos, side, false); + } + resolveInner(pos, side = 0) { + return resolveNode(this, pos, side, true); + } + enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); } + /// @internal + toString() { return this.context.buffer.childString(this.index); } + getChild(type, before = null, after = null) { + let r = getChildren(this, type, before, after); + return r.length ? r[0] : null; + } + getChildren(type, before = null, after = null) { + return getChildren(this, type, before, after); + } +} +/// A tree cursor object focuses on a given node in a syntax tree, and +/// allows you to move to adjacent nodes. +class TreeCursor { + /// @internal + constructor(node, + /// @internal + mode = 0) { + this.mode = mode; + this.buffer = null; + this.stack = []; + this.index = 0; + this.bufferNode = null; + if (node instanceof TreeNode) { + this.yieldNode(node); } - if (from > 0) { - let first = nodes[0]; - if (first instanceof HeightMapGap) - nodes[0] = new HeightMapGap(from + first.length); - else - nodes.unshift(new HeightMapGap(from - 1), null); + else { + this._tree = node.context.parent; + this.buffer = node.context; + for (let n = node._parent; n; n = n._parent) + this.stack.unshift(n.index); + this.bufferNode = node; + this.yieldBuf(node.index); } - return HeightMap.of(nodes); } - decomposeLeft(to, result) { - result.push(new HeightMapGap(to - 1), null); + /// Shorthand for `.type.name`. + get name() { return this.type.name; } + yieldNode(node) { + if (!node) + return false; + this._tree = node; + this.type = node.type; + this.from = node.from; + this.to = node.to; + return true; } - decomposeRight(from, result) { - result.push(null, new HeightMapGap(this.length - from - 1)); + yieldBuf(index, type) { + this.index = index; + let { start, buffer } = this.buffer; + this.type = type || buffer.set.types[buffer.buffer[index]]; + this.from = start + buffer.buffer[index + 1]; + this.to = start + buffer.buffer[index + 2]; + return true; } - updateHeight(oracle, offset = 0, force = false, measured) { - let end = offset + this.length; - if (measured && measured.from <= offset + this.length && measured.more) { - // Fill in part of this gap with measured lines. We know there - // can't be widgets or collapsed ranges in those lines, because - // they would already have been added to the heightmap (gaps - // only contain plain text). - let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1; - let wasChanged = oracle.heightChanged; - if (measured.from > offset) - nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset)); - while (pos <= end && measured.more) { - let len = oracle.doc.lineAt(pos).length; - if (nodes.length) - nodes.push(null); - let height = measured.heights[measured.index++]; - if (singleHeight == -1) - singleHeight = height; - else if (Math.abs(height - singleHeight) >= Epsilon) - singleHeight = -2; - let line = new HeightMapText(len, height); - line.outdated = false; - nodes.push(line); - pos += len + 1; - } - if (pos <= end) - nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos)); - let result = HeightMap.of(nodes); - oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon || - Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon; - return result; - } - else if (force || this.outdated) { - this.setHeight(oracle, oracle.heightForGap(offset, offset + this.length)); - this.outdated = false; + yield(node) { + if (!node) + return false; + if (node instanceof TreeNode) { + this.buffer = null; + return this.yieldNode(node); } - return this; + this.buffer = node.context; + return this.yieldBuf(node.index, node.type); } - toString() { return `gap(${this.length})`; } -} -class HeightMapBranch extends HeightMap { - constructor(left, brk, right) { - super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Outdated */ : 0)); - this.left = left; - this.right = right; - this.size = left.size + right.size; + /// @internal + toString() { + return this.buffer ? this.buffer.buffer.childString(this.index) : this._tree.toString(); } - get break() { return this.flags & 1 /* Break */; } - blockAt(height, doc, top, offset) { - let mid = top + this.left.height; - return height < mid ? this.left.blockAt(height, doc, top, offset) - : this.right.blockAt(height, doc, mid, offset + this.left.length + this.break); + /// @internal + enterChild(dir, pos, side) { + if (!this.buffer) + return this.yield(this._tree.nextChild(dir < 0 ? this._tree.node.children.length - 1 : 0, dir, pos, side, this.mode)); + let { buffer } = this.buffer; + let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side); + if (index < 0) + return false; + this.stack.push(this.index); + return this.yieldBuf(index); } - lineAt(value, type, doc, top, offset) { - let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break; - let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset; - let base = left ? this.left.lineAt(value, type, doc, top, offset) - : this.right.lineAt(value, type, doc, rightTop, rightOffset); - if (this.break || (left ? base.to < rightOffset : base.from > rightOffset)) - return base; - let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos; - if (left) - return base.join(this.right.lineAt(rightOffset, subQuery, doc, rightTop, rightOffset)); - else - return this.left.lineAt(rightOffset, subQuery, doc, top, offset).join(base); + /// Move the cursor to this node's first child. When this returns + /// false, the node has no child, and the cursor has not been moved. + firstChild() { return this.enterChild(1, 0, 4 /* DontCare */); } + /// Move the cursor to this node's last child. + lastChild() { return this.enterChild(-1, 0, 4 /* DontCare */); } + /// Move the cursor to the first child that ends after `pos`. + childAfter(pos) { return this.enterChild(1, pos, 2 /* After */); } + /// Move to the last child that starts before `pos`. + childBefore(pos) { return this.enterChild(-1, pos, -2 /* Before */); } + /// Move the cursor to the child around `pos`. If side is -1 the + /// child may end at that position, when 1 it may start there. This + /// will also enter [overlaid](#common.MountedTree.overlay) + /// [mounted](#common.NodeProp^mounted) trees unless `overlays` is + /// set to false. + enter(pos, side, overlays = true, buffers = true) { + if (!this.buffer) + return this.yield(this._tree.enter(pos, side, overlays && !(this.mode & 1 /* Full */), buffers)); + return buffers ? this.enterChild(1, pos, side) : false; } - forEachLine(from, to, doc, top, offset, f) { - let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break; - if (this.break) { - if (from < rightOffset) - this.left.forEachLine(from, to, doc, top, offset, f); - if (to >= rightOffset) - this.right.forEachLine(from, to, doc, rightTop, rightOffset, f); + /// Move to the node's parent node, if this isn't the top node. + parent() { + if (!this.buffer) + return this.yieldNode((this.mode & 1 /* Full */) ? this._tree._parent : this._tree.parent); + if (this.stack.length) + return this.yieldBuf(this.stack.pop()); + let parent = (this.mode & 1 /* Full */) ? this.buffer.parent : this.buffer.parent.nextSignificantParent(); + this.buffer = null; + return this.yieldNode(parent); + } + /// @internal + sibling(dir) { + if (!this.buffer) + return !this._tree._parent ? false + : this.yield(this._tree.index < 0 ? null + : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4 /* DontCare */, this.mode)); + let { buffer } = this.buffer, d = this.stack.length - 1; + if (dir < 0) { + let parentStart = d < 0 ? 0 : this.stack[d] + 4; + if (this.index != parentStart) + return this.yieldBuf(buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */)); } else { - let mid = this.lineAt(rightOffset, QueryType.ByPos, doc, top, offset); - if (from < mid.from) - this.left.forEachLine(from, mid.from - 1, doc, top, offset, f); - if (mid.to >= from && mid.from <= to) - f(mid); - if (to > mid.to) - this.right.forEachLine(mid.to + 1, to, doc, rightTop, rightOffset, f); - } - } - replace(from, to, nodes) { - let rightStart = this.left.length + this.break; - if (to < rightStart) - return this.balanced(this.left.replace(from, to, nodes), this.right); - if (from > this.left.length) - return this.balanced(this.left, this.right.replace(from - rightStart, to - rightStart, nodes)); - let result = []; - if (from > 0) - this.decomposeLeft(from, result); - let left = result.length; - for (let node of nodes) - result.push(node); - if (from > 0) - mergeGaps(result, left - 1); - if (to < this.length) { - let right = result.length; - this.decomposeRight(to, result); - mergeGaps(result, right); + let after = buffer.buffer[this.index + 3]; + if (after < (d < 0 ? buffer.buffer.length : buffer.buffer[this.stack[d] + 3])) + return this.yieldBuf(after); } - return HeightMap.of(result); + return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4 /* DontCare */, this.mode)) : false; } - decomposeLeft(to, result) { - let left = this.left.length; - if (to <= left) - return this.left.decomposeLeft(to, result); - result.push(this.left); - if (this.break) { - left++; - if (to >= left) - result.push(null); + /// Move to this node's next sibling, if any. + nextSibling() { return this.sibling(1); } + /// Move to this node's previous sibling, if any. + prevSibling() { return this.sibling(-1); } + atLastNode(dir) { + let index, parent, { buffer } = this; + if (buffer) { + if (dir > 0) { + if (this.index < buffer.buffer.buffer.length) + return false; + } + else { + for (let i = 0; i < this.index; i++) + if (buffer.buffer.buffer[i + 3] < this.index) + return false; + } + ({ index, parent } = buffer); } - if (to > left) - this.right.decomposeLeft(to - left, result); + else { + ({ index, _parent: parent } = this._tree); + } + for (; parent; { index, _parent: parent } = parent) { + if (index > -1) + for (let i = index + dir, e = dir < 0 ? -1 : parent.node.children.length; i != e; i += dir) { + let child = parent.node.children[i]; + if ((this.mode & 1 /* Full */) || child instanceof TreeBuffer || !child.type.isAnonymous || hasChild(child)) + return false; + } + } + return true; } - decomposeRight(from, result) { - let left = this.left.length, right = left + this.break; - if (from >= right) - return this.right.decomposeRight(from - right, result); - if (from < left) - this.left.decomposeRight(from, result); - if (this.break && from < right) - result.push(null); - result.push(this.right); + move(dir, enter) { + if (enter && this.enterChild(dir, 0, 4 /* DontCare */)) + return true; + for (;;) { + if (this.sibling(dir)) + return true; + if (this.atLastNode(dir) || !this.parent()) + return false; + } } - balanced(left, right) { - if (left.size > 2 * right.size || right.size > 2 * left.size) - return HeightMap.of(this.break ? [left, null, right] : [left, right]); - this.left = left; - this.right = right; - this.height = left.height + right.height; - this.outdated = left.outdated || right.outdated; - this.size = left.size + right.size; - this.length = left.length + this.break + right.length; + /// Move to the next node in a + /// [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR)) + /// traversal, going from a node to its first child or, if the + /// current node is empty or `enter` is false, its next sibling or + /// the next sibling of the first parent node that has one. + next(enter = true) { return this.move(1, enter); } + /// Move to the next node in a last-to-first pre-order traveral. A + /// node is followed by its last child or, if it has none, its + /// previous sibling or the previous sibling of the first parent + /// node that has one. + prev(enter = true) { return this.move(-1, enter); } + /// Move the cursor to the innermost node that covers `pos`. If + /// `side` is -1, it will enter nodes that end at `pos`. If it is 1, + /// it will enter nodes that start at `pos`. + moveTo(pos, side = 0) { + // Move up to a node that actually holds the position, if possible + while (this.from == this.to || + (side < 1 ? this.from >= pos : this.from > pos) || + (side > -1 ? this.to <= pos : this.to < pos)) + if (!this.parent()) + break; + // Then scan down into child nodes as far as possible + while (this.enterChild(1, pos, side)) { } return this; } - updateHeight(oracle, offset = 0, force = false, measured) { - let { left, right } = this, rightStart = offset + left.length + this.break, rebalance = null; - if (measured && measured.from <= offset + left.length && measured.more) - rebalance = left = left.updateHeight(oracle, offset, force, measured); - else - left.updateHeight(oracle, offset, force); - if (measured && measured.from <= rightStart + right.length && measured.more) - rebalance = right = right.updateHeight(oracle, rightStart, force, measured); - else - right.updateHeight(oracle, rightStart, force); - if (rebalance) - return this.balanced(left, right); - this.height = this.left.height + this.right.height; - this.outdated = false; - return this; + /// Get a [syntax node](#common.SyntaxNode) at the cursor's current + /// position. + get node() { + if (!this.buffer) + return this._tree; + let cache = this.bufferNode, result = null, depth = 0; + if (cache && cache.context == this.buffer) { + scan: for (let index = this.index, d = this.stack.length; d >= 0;) { + for (let c = cache; c; c = c._parent) + if (c.index == index) { + if (index == this.index) + return c; + result = c; + depth = d + 1; + break scan; + } + index = this.stack[--d]; + } + } + for (let i = depth; i < this.stack.length; i++) + result = new BufferNode(this.buffer, result, this.stack[i]); + return this.bufferNode = new BufferNode(this.buffer, result, this.index); + } + /// Get the [tree](#common.Tree) that represents the current node, if + /// any. Will return null when the node is in a [tree + /// buffer](#common.TreeBuffer). + get tree() { + return this.buffer ? null : this._tree.node; } - toString() { return this.left + (this.break ? " " : "-") + this.right; } } -function mergeGaps(nodes, around) { - let before, after; - if (nodes[around] == null && - (before = nodes[around - 1]) instanceof HeightMapGap && - (after = nodes[around + 1]) instanceof HeightMapGap) - nodes.splice(around - 1, 3, new HeightMapGap(before.length + 1 + after.length)); +function hasChild(tree) { + return tree.children.some(ch => ch instanceof TreeBuffer || !ch.type.isAnonymous || hasChild(ch)); } -const relevantWidgetHeight = 5; -class NodeBuilder { - constructor(pos, oracle) { - this.pos = pos; - this.oracle = oracle; - this.nodes = []; - this.lineStart = -1; - this.lineEnd = -1; - this.covering = null; - this.writtenTo = pos; - } - get isCovered() { - return this.covering && this.nodes[this.nodes.length - 1] == this.covering; - } - span(_from, to) { - if (this.lineStart > -1) { - let end = Math.min(to, this.lineEnd), last = this.nodes[this.nodes.length - 1]; - if (last instanceof HeightMapText) - last.length += end - this.pos; - else if (end > this.pos || !this.isCovered) - this.nodes.push(new HeightMapText(end - this.pos, -1)); - this.writtenTo = end; - if (to > end) { - this.nodes.push(null); - this.writtenTo++; - this.lineStart = -1; +function buildTree(data) { + var _a; + let { buffer, nodeSet, maxBufferLength = DefaultBufferLength, reused = [], minRepeatType = nodeSet.types.length } = data; + let cursor = Array.isArray(buffer) ? new FlatBufferCursor(buffer, buffer.length) : buffer; + let types = nodeSet.types; + let contextHash = 0, lookAhead = 0; + function takeNode(parentStart, minPos, children, positions, inRepeat) { + let { id, start, end, size } = cursor; + let lookAheadAtStart = lookAhead; + while (size < 0) { + cursor.next(); + if (size == -1 /* Reuse */) { + let node = reused[id]; + children.push(node); + positions.push(start - parentStart); + return; } - } - this.pos = to; - } - point(from, to, deco) { - if (from < to || deco.heightRelevant) { - let height = deco.widget ? deco.widget.estimatedHeight : 0; - if (height < 0) - height = this.oracle.lineHeight; - let len = to - from; - if (deco.block) { - this.addBlock(new HeightMapBlock(len, height, deco.type)); + else if (size == -3 /* ContextChange */) { // Context change + contextHash = id; + return; } - else if (len || height >= relevantWidgetHeight) { - this.addLineDeco(height, len); + else if (size == -4 /* LookAhead */) { + lookAhead = id; + return; + } + else { + throw new RangeError(`Unrecognized record size: ${size}`); } } - else if (to > from) { - this.span(from, to); + let type = types[id], node, buffer; + let startPos = start - parentStart; + if (end - start <= maxBufferLength && (buffer = findBufferSize(cursor.pos - minPos, inRepeat))) { + // Small enough for a buffer, and no reused nodes inside + let data = new Uint16Array(buffer.size - buffer.skip); + let endPos = cursor.pos - buffer.size, index = data.length; + while (cursor.pos > endPos) + index = copyToBuffer(buffer.start, data, index); + node = new TreeBuffer(data, end - buffer.start, nodeSet); + startPos = buffer.start - parentStart; } - if (this.lineEnd > -1 && this.lineEnd < this.pos) - this.lineEnd = this.oracle.doc.lineAt(this.pos).to; - } - enterLine() { - if (this.lineStart > -1) - return; - let { from, to } = this.oracle.doc.lineAt(this.pos); - this.lineStart = from; - this.lineEnd = to; - if (this.writtenTo < from) { - if (this.writtenTo < from - 1 || this.nodes[this.nodes.length - 1] == null) - this.nodes.push(this.blankContent(this.writtenTo, from - 1)); - this.nodes.push(null); + else { // Make it a node + let endPos = cursor.pos - size; + cursor.next(); + let localChildren = [], localPositions = []; + let localInRepeat = id >= minRepeatType ? id : -1; + let lastGroup = 0, lastEnd = end; + while (cursor.pos > endPos) { + if (localInRepeat >= 0 && cursor.id == localInRepeat && cursor.size >= 0) { + if (cursor.end <= lastEnd - maxBufferLength) { + makeRepeatLeaf(localChildren, localPositions, start, lastGroup, cursor.end, lastEnd, localInRepeat, lookAheadAtStart); + lastGroup = localChildren.length; + lastEnd = cursor.end; + } + cursor.next(); + } + else { + takeNode(start, endPos, localChildren, localPositions, localInRepeat); + } + } + if (localInRepeat >= 0 && lastGroup > 0 && lastGroup < localChildren.length) + makeRepeatLeaf(localChildren, localPositions, start, lastGroup, start, lastEnd, localInRepeat, lookAheadAtStart); + localChildren.reverse(); + localPositions.reverse(); + if (localInRepeat > -1 && lastGroup > 0) { + let make = makeBalanced(type); + node = balanceRange(type, localChildren, localPositions, 0, localChildren.length, 0, end - start, make, make); + } + else { + node = makeTree(type, localChildren, localPositions, end - start, lookAheadAtStart - end); + } } - if (this.pos > from) - this.nodes.push(new HeightMapText(this.pos - from, -1)); - this.writtenTo = this.pos; - } - blankContent(from, to) { - let gap = new HeightMapGap(to - from); - if (this.oracle.doc.lineAt(from).to == to) - gap.flags |= 4 /* SingleLine */; - return gap; + children.push(node); + positions.push(startPos); } - ensureLine() { - this.enterLine(); - let last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null; - if (last instanceof HeightMapText) - return last; - let line = new HeightMapText(0, -1); - this.nodes.push(line); - return line; + function makeBalanced(type) { + return (children, positions, length) => { + let lookAhead = 0, lastI = children.length - 1, last, lookAheadProp; + if (lastI >= 0 && (last = children[lastI]) instanceof Tree) { + if (!lastI && last.type == type && last.length == length) + return last; + if (lookAheadProp = last.prop(NodeProp.lookAhead)) + lookAhead = positions[lastI] + last.length + lookAheadProp; + } + return makeTree(type, children, positions, length, lookAhead); + }; } - addBlock(block) { - this.enterLine(); - if (block.type == exports.BlockType.WidgetAfter && !this.isCovered) - this.ensureLine(); - this.nodes.push(block); - this.writtenTo = this.pos = this.pos + block.length; - if (block.type != exports.BlockType.WidgetBefore) - this.covering = block; + function makeRepeatLeaf(children, positions, base, i, from, to, type, lookAhead) { + let localChildren = [], localPositions = []; + while (children.length > i) { + localChildren.push(children.pop()); + localPositions.push(positions.pop() + base - from); + } + children.push(makeTree(nodeSet.types[type], localChildren, localPositions, to - from, lookAhead - to)); + positions.push(from - base); } - addLineDeco(height, length) { - let line = this.ensureLine(); - line.length += length; - line.collapsed += length; - line.widgetHeight = Math.max(line.widgetHeight, height); - this.writtenTo = this.pos = this.pos + length; + function makeTree(type, children, positions, length, lookAhead = 0, props) { + if (contextHash) { + let pair = [NodeProp.contextHash, contextHash]; + props = props ? [pair].concat(props) : [pair]; + } + if (lookAhead > 25) { + let pair = [NodeProp.lookAhead, lookAhead]; + props = props ? [pair].concat(props) : [pair]; + } + return new Tree(type, children, positions, length, props); } - finish(from) { - let last = this.nodes.length == 0 ? null : this.nodes[this.nodes.length - 1]; - if (this.lineStart > -1 && !(last instanceof HeightMapText) && !this.isCovered) - this.nodes.push(new HeightMapText(0, -1)); - else if (this.writtenTo < this.pos || last == null) - this.nodes.push(this.blankContent(this.writtenTo, this.pos)); - let pos = from; - for (let node of this.nodes) { - if (node instanceof HeightMapText) - node.updateHeight(this.oracle, pos); - pos += node ? node.length : 1; + function findBufferSize(maxSize, inRepeat) { + // Scan through the buffer to find previous siblings that fit + // together in a TreeBuffer, and don't contain any reused nodes + // (which can't be stored in a buffer). + // If `inRepeat` is > -1, ignore node boundaries of that type for + // nesting, but make sure the end falls either at the start + // (`maxSize`) or before such a node. + let fork = cursor.fork(); + let size = 0, start = 0, skip = 0, minStart = fork.end - maxBufferLength; + let result = { size: 0, start: 0, skip: 0 }; + scan: for (let minPos = fork.pos - maxSize; fork.pos > minPos;) { + let nodeSize = fork.size; + // Pretend nested repeat nodes of the same type don't exist + if (fork.id == inRepeat && nodeSize >= 0) { + // Except that we store the current state as a valid return + // value. + result.size = size; + result.start = start; + result.skip = skip; + skip += 4; + size += 4; + fork.next(); + continue; + } + let startPos = fork.pos - nodeSize; + if (nodeSize < 0 || startPos < minPos || fork.start < minStart) + break; + let localSkipped = fork.id >= minRepeatType ? 4 : 0; + let nodeStart = fork.start; + fork.next(); + while (fork.pos > startPos) { + if (fork.size < 0) { + if (fork.size == -3 /* ContextChange */) + localSkipped += 4; + else + break scan; + } + else if (fork.id >= minRepeatType) { + localSkipped += 4; + } + fork.next(); + } + start = nodeStart; + size += nodeSize; + skip += localSkipped; } - return this.nodes; + if (inRepeat < 0 || size == maxSize) { + result.size = size; + result.start = start; + result.skip = skip; + } + return result.size > 4 ? result : undefined; } - // Always called with a region that on both sides either stretches - // to a line break or the end of the document. - // The returned array uses null to indicate line breaks, but never - // starts or ends in a line break, or has multiple line breaks next - // to each other. - static build(oracle, decorations, from, to) { - let builder = new NodeBuilder(from, oracle); - rangeset.RangeSet.spans(decorations, from, to, builder, 0); - return builder.finish(from); + function copyToBuffer(bufferStart, buffer, index) { + let { id, start, end, size } = cursor; + cursor.next(); + if (size >= 0 && id < minRepeatType) { + let startIndex = index; + if (size > 4) { + let endPos = cursor.pos - (size - 4); + while (cursor.pos > endPos) + index = copyToBuffer(bufferStart, buffer, index); + } + buffer[--index] = startIndex; + buffer[--index] = end - bufferStart; + buffer[--index] = start - bufferStart; + buffer[--index] = id; + } + else if (size == -3 /* ContextChange */) { + contextHash = id; + } + else if (size == -4 /* LookAhead */) { + lookAhead = id; + } + return index; } + let children = [], positions = []; + while (cursor.pos > 0) + takeNode(data.start || 0, data.bufferStart || 0, children, positions, -1); + let length = (_a = data.length) !== null && _a !== void 0 ? _a : (children.length ? positions[0] + children[0].length : 0); + return new Tree(types[data.topID], children.reverse(), positions.reverse(), length); } -function heightRelevantDecoChanges(a, b, diff) { - let comp = new DecorationComparator; - rangeset.RangeSet.compare(a, b, diff, comp, 0); - return comp.changes; -} -class DecorationComparator { - constructor() { - this.changes = []; - } - compareRange() { } - comparePoint(from, to, a, b) { - if (from < to || a && a.heightRelevant || b && b.heightRelevant) - addRange(from, to, this.changes, 5); +const nodeSizeCache = new WeakMap; +function nodeSize(balanceType, node) { + if (!balanceType.isAnonymous || node instanceof TreeBuffer || node.type != balanceType) + return 1; + let size = nodeSizeCache.get(node); + if (size == null) { + size = 1; + for (let child of node.children) { + if (child.type != balanceType || !(child instanceof Tree)) { + size = 1; + break; + } + size += nodeSize(balanceType, child); + } + nodeSizeCache.set(node, size); } + return size; } - -function visiblePixelRange(dom, paddingTop) { - let rect = dom.getBoundingClientRect(); - let left = Math.max(0, rect.left), right = Math.min(innerWidth, rect.right); - let top = Math.max(0, rect.top), bottom = Math.min(innerHeight, rect.bottom); - let body = dom.ownerDocument.body; - for (let parent = dom.parentNode; parent && parent != body;) { - if (parent.nodeType == 1) { - let elt = parent; - let style = window.getComputedStyle(elt); - if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) && - style.overflow != "visible") { - let parentRect = elt.getBoundingClientRect(); - left = Math.max(left, parentRect.left); - right = Math.min(right, parentRect.right); - top = Math.max(top, parentRect.top); - bottom = Math.min(bottom, parentRect.bottom); +function balanceRange( +// The type the balanced tree's inner nodes. +balanceType, +// The direct children and their positions +children, positions, +// The index range in children/positions to use +from, to, +// The start position of the nodes, relative to their parent. +start, +// Length of the outer node +length, +// Function to build the top node of the balanced tree +mkTop, +// Function to build internal nodes for the balanced tree +mkTree) { + let total = 0; + for (let i = from; i < to; i++) + total += nodeSize(balanceType, children[i]); + let maxChild = Math.ceil((total * 1.5) / 8 /* BranchFactor */); + let localChildren = [], localPositions = []; + function divide(children, positions, from, to, offset) { + for (let i = from; i < to;) { + let groupFrom = i, groupStart = positions[i], groupSize = nodeSize(balanceType, children[i]); + i++; + for (; i < to; i++) { + let nextSize = nodeSize(balanceType, children[i]); + if (groupSize + nextSize >= maxChild) + break; + groupSize += nextSize; } - parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode; - } - else if (parent.nodeType == 11) { // Shadow root - parent = parent.host; - } - else { - break; + if (i == groupFrom + 1) { + if (groupSize > maxChild) { + let only = children[groupFrom]; // Only trees can have a size > 1 + divide(only.children, only.positions, 0, only.children.length, positions[groupFrom] + offset); + continue; + } + localChildren.push(children[groupFrom]); + } + else { + let length = positions[i - 1] + children[i - 1].length - groupStart; + localChildren.push(balanceRange(balanceType, children, positions, groupFrom, i, groupStart, length, null, mkTree)); + } + localPositions.push(groupStart + offset - start); } } - return { left: left - rect.left, right: Math.max(left, right) - rect.left, - top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) }; + divide(children, positions, from, to, 0); + return (mkTop || mkTree)(localChildren, localPositions, length); } -// Line gaps are placeholder widgets used to hide pieces of overlong -// lines within the viewport, as a kludge to keep the editor -// responsive when a ridiculously long line is loaded into it. -class LineGap { - constructor(from, to, size) { + +/// Tree fragments are used during [incremental +/// parsing](#common.Parser.startParse) to track parts of old trees +/// that can be reused in a new parse. An array of fragments is used +/// to track regions of an old tree whose nodes might be reused in new +/// parses. Use the static +/// [`applyChanges`](#common.TreeFragment^applyChanges) method to +/// update fragments for document changes. +class TreeFragment { + /// Construct a tree fragment. + constructor( + /// The start of the unchanged range pointed to by this fragment. + /// This refers to an offset in the _updated_ document (as opposed + /// to the original tree). + from, + /// The end of the unchanged range. + to, + /// The tree that this fragment is based on. + tree, + /// The offset between the fragment's tree and the document that + /// this fragment can be used against. Add this when going from + /// document to tree positions, subtract it to go from tree to + /// document positions. + offset, openStart = false, openEnd = false) { this.from = from; this.to = to; - this.size = size; + this.tree = tree; + this.offset = offset; + this.open = (openStart ? 1 /* Start */ : 0) | (openEnd ? 2 /* End */ : 0); } - static same(a, b) { - if (a.length != b.length) - return false; - for (let i = 0; i < a.length; i++) { - let gA = a[i], gB = b[i]; - if (gA.from != gB.from || gA.to != gB.to || gA.size != gB.size) - return false; - } - return true; + /// Whether the start of the fragment represents the start of a + /// parse, or the end of a change. (In the second case, it may not + /// be safe to reuse some nodes at the start, depending on the + /// parsing algorithm.) + get openStart() { return (this.open & 1 /* Start */) > 0; } + /// Whether the end of the fragment represents the end of a + /// full-document parse, or the start of a change. + get openEnd() { return (this.open & 2 /* End */) > 0; } + /// Create a set of fragments from a freshly parsed tree, or update + /// an existing set of fragments by replacing the ones that overlap + /// with a tree with content from the new tree. When `partial` is + /// true, the parse is treated as incomplete, and the resulting + /// fragment has [`openEnd`](#common.TreeFragment.openEnd) set to + /// true. + static addTree(tree, fragments = [], partial = false) { + let result = [new TreeFragment(0, tree.length, tree, 0, false, partial)]; + for (let f of fragments) + if (f.to > tree.length) + result.push(f); + return result; } - draw(wrapping) { - return Decoration.replace({ widget: new LineGapWidget(this.size, wrapping) }).range(this.from, this.to); + /// Apply a set of edits to an array of fragments, removing or + /// splitting fragments as necessary to remove edited ranges, and + /// adjusting offsets for fragments that moved. + static applyChanges(fragments, changes, minGap = 128) { + if (!changes.length) + return fragments; + let result = []; + let fI = 1, nextF = fragments.length ? fragments[0] : null; + for (let cI = 0, pos = 0, off = 0;; cI++) { + let nextC = cI < changes.length ? changes[cI] : null; + let nextPos = nextC ? nextC.fromA : 1e9; + if (nextPos - pos >= minGap) + while (nextF && nextF.from < nextPos) { + let cut = nextF; + if (pos >= cut.from || nextPos <= cut.to || off) { + let fFrom = Math.max(cut.from, pos) - off, fTo = Math.min(cut.to, nextPos) - off; + cut = fFrom >= fTo ? null : new TreeFragment(fFrom, fTo, cut.tree, cut.offset + off, cI > 0, !!nextC); + } + if (cut) + result.push(cut); + if (nextF.to > nextPos) + break; + nextF = fI < fragments.length ? fragments[fI++] : null; + } + if (!nextC) + break; + pos = nextC.toA; + off = nextC.toA - nextC.toB; + } + return result; } } -class LineGapWidget extends WidgetType { - constructor(size, vertical) { - super(); - this.size = size; - this.vertical = vertical; +/// A superclass that parsers should extend. +class Parser { + /// Start a parse, returning a [partial parse](#common.PartialParse) + /// object. [`fragments`](#common.TreeFragment) can be passed in to + /// make the parse incremental. + /// + /// By default, the entire input is parsed. You can pass `ranges`, + /// which should be a sorted array of non-empty, non-overlapping + /// ranges, to parse only those ranges. The tree returned in that + /// case will start at `ranges[0].from`. + startParse(input, fragments, ranges) { + if (typeof input == "string") + input = new StringInput(input); + ranges = !ranges ? [new Range(0, input.length)] : ranges.length ? ranges.map(r => new Range(r.from, r.to)) : [new Range(0, 0)]; + return this.createParse(input, fragments || [], ranges); } - eq(other) { return other.size == this.size && other.vertical == this.vertical; } - toDOM() { - let elt = document.createElement("div"); - if (this.vertical) { - elt.style.height = this.size + "px"; - } - else { - elt.style.width = this.size + "px"; - elt.style.height = "2px"; - elt.style.display = "inline-block"; + /// Run a full parse, returning the resulting tree. + parse(input, fragments, ranges) { + let parse = this.startParse(input, fragments, ranges); + for (;;) { + let done = parse.advance(); + if (done) + return done; } - return elt; } - get estimatedHeight() { return this.vertical ? this.size : -1; } } -class ViewState { - constructor(state) { - this.state = state; - // These are contentDOM-local coordinates - this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 }; - this.inView = true; - this.paddingTop = 0; - this.paddingBottom = 0; - this.contentDOMWidth = 0; - this.contentDOMHeight = 0; - this.editorHeight = 0; - this.editorWidth = 0; - this.heightOracle = new HeightOracle; - // See VP.MaxDOMHeight - this.scaler = IdScaler; - this.scrollTarget = null; - // Briefly set to true when printing, to disable viewport limiting - this.printing = false; - // Flag set when editor content was redrawn, so that the next - // measure stage knows it must read DOM layout - this.mustMeasureContent = true; - this.visibleRanges = []; - // Cursor 'assoc' is only significant when the cursor is on a line - // wrap point, where it must stick to the character that it is - // associated with. Since browsers don't provide a reasonable - // interface to set or query this, when a selection is set that - // might cause this to be significant, this flag is set. The next - // measure phase will check whether the cursor is on a line-wrapping - // boundary and, if so, reset it to make sure it is positioned in - // the right place. - this.mustEnforceCursorAssoc = false; - this.heightMap = HeightMap.empty().applyChanges(state.facet(decorations), text.Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]); - this.viewport = this.getViewport(0, null); - this.updateViewportLines(); - this.updateForViewport(); - this.lineGaps = this.ensureLineGaps([]); - this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false))); - this.computeVisibleRanges(); +class StringInput { + constructor(string) { + this.string = string; } - updateForViewport() { - let viewports = [this.viewport], { main } = this.state.selection; - for (let i = 0; i <= 1; i++) { - let pos = i ? main.head : main.anchor; - if (!viewports.some(({ from, to }) => pos >= from && pos <= to)) { - let { from, to } = this.lineBlockAt(pos); - viewports.push(new Viewport(from, to)); - } - } - this.viewports = viewports.sort((a, b) => a.from - b.from); - this.scaler = this.heightMap.height <= 7000000 /* MaxDOMHeight */ ? IdScaler : - new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports); + get length() { return this.string.length; } + chunk(from) { return this.string.slice(from); } + get lineChunks() { return false; } + read(from, to) { return this.string.slice(from, to); } +} + +/// Create a parse wrapper that, after the inner parse completes, +/// scans its tree for mixed language regions with the `nest` +/// function, runs the resulting [inner parses](#common.NestedParse), +/// and then [mounts](#common.NodeProp^mounted) their results onto the +/// tree. +/// +/// The nesting function is passed a cursor to provide context for a +/// node, but _should not_ move that cursor, only inspect its +/// properties and optionally access its +/// [node object](#common.TreeCursor.node). +function parseMixed(nest) { + return (parse, input, fragments, ranges) => new MixedParse(parse, nest, input, fragments, ranges); +} +class InnerParse { + constructor(parser, parse, overlay, target, ranges) { + this.parser = parser; + this.parse = parse; + this.overlay = overlay; + this.target = target; + this.ranges = ranges; } - updateViewportLines() { - this.viewportLines = []; - this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => { - this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler)); - }); +} +class ActiveOverlay { + constructor(parser, predicate, mounts, index, start, target, prev) { + this.parser = parser; + this.predicate = predicate; + this.mounts = mounts; + this.index = index; + this.start = start; + this.target = target; + this.prev = prev; + this.depth = 0; + this.ranges = []; } - update(update, scrollTarget = null) { - let prev = this.state; - this.state = update.state; - let newDeco = this.state.facet(decorations); - let contentChanges = update.changedRanges; - let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(update.startState.facet(decorations), newDeco, update ? update.changes : state.ChangeSet.empty(this.state.doc.length))); - let prevHeight = this.heightMap.height; - this.heightMap = this.heightMap.applyChanges(newDeco, prev.doc, this.heightOracle.setDoc(this.state.doc), heightChanges); - if (this.heightMap.height != prevHeight) - update.flags |= 2 /* Height */; - let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport; - if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) || - !this.viewportIsAppropriate(viewport)) - viewport = this.getViewport(0, scrollTarget); - let updateLines = !update.changes.empty || (update.flags & 2 /* Height */) || - viewport.from != this.viewport.from || viewport.to != this.viewport.to; - this.viewport = viewport; - this.updateForViewport(); - if (updateLines) - this.updateViewportLines(); - if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */) - this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes))); - update.flags |= this.computeVisibleRanges(); - if (scrollTarget) - this.scrollTarget = scrollTarget; - if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping && - update.state.selection.main.empty && update.state.selection.main.assoc) - this.mustEnforceCursorAssoc = true; +} +const stoppedInner = new NodeProp({ perNode: true }); +class MixedParse { + constructor(base, nest, input, fragments, ranges) { + this.nest = nest; + this.input = input; + this.fragments = fragments; + this.ranges = ranges; + this.inner = []; + this.innerDone = 0; + this.baseTree = null; + this.stoppedAt = null; + this.baseParse = base; } - measure(view) { - let dom = view.contentDOM, style = window.getComputedStyle(dom); - let oracle = this.heightOracle; - let whiteSpace = style.whiteSpace, direction = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR; - let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction); - let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight; - let result = 0, bias = 0; - if (this.editorWidth != view.scrollDOM.clientWidth) { - if (oracle.lineWrapping) - measureContent = true; - this.editorWidth = view.scrollDOM.clientWidth; - result |= 8 /* Geometry */; + advance() { + if (this.baseParse) { + let done = this.baseParse.advance(); + if (!done) + return null; + this.baseParse = null; + this.baseTree = done; + this.startInner(); + if (this.stoppedAt != null) + for (let inner of this.inner) + inner.parse.stopAt(this.stoppedAt); } - if (measureContent) { - this.mustMeasureContent = false; - this.contentDOMHeight = dom.clientHeight; - // Vertical padding - let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0; - if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) { - result |= 8 /* Geometry */; - this.paddingTop = paddingTop; - this.paddingBottom = paddingBottom; - } + if (this.innerDone == this.inner.length) { + let result = this.baseTree; + if (this.stoppedAt != null) + result = new Tree(result.type, result.children, result.positions, result.length, result.propValues.concat([[stoppedInner, this.stoppedAt]])); + return result; } - // Pixel viewport - let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 } - : visiblePixelRange(dom, this.paddingTop); - let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom; - this.pixelViewport = pixelViewport; - let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left; - if (inView != this.inView) { - this.inView = inView; - if (inView) - measureContent = true; + let inner = this.inner[this.innerDone], done = inner.parse.advance(); + if (done) { + this.innerDone++; + // This is a somewhat dodgy but super helpful hack where we + // patch up nodes created by the inner parse (and thus + // presumably not aliased anywhere else) to hold the information + // about the inner parse. + let props = Object.assign(Object.create(null), inner.target.props); + props[NodeProp.mounted.id] = new MountedTree(done, inner.overlay, inner.parser); + inner.target.props = props; } - if (!this.inView) + return null; + } + get parsedPos() { + if (this.baseParse) return 0; - let contentWidth = dom.clientWidth; - if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) { - this.contentDOMWidth = contentWidth; - this.editorHeight = view.scrollDOM.clientHeight; - result |= 8 /* Geometry */; + let pos = this.input.length; + for (let i = this.innerDone; i < this.inner.length; i++) { + if (this.inner[i].ranges[0].from < pos) + pos = Math.min(pos, this.inner[i].parse.parsedPos); } - if (measureContent) { - let lineHeights = view.docView.measureVisibleLineHeights(); - if (oracle.mustRefreshForHeights(lineHeights)) - refresh = true; - if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) { - let { lineHeight, charWidth } = view.docView.measureTextSize(); - refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights); - if (refresh) { - view.docView.minWidth = 0; - result |= 8 /* Geometry */; + return pos; + } + stopAt(pos) { + this.stoppedAt = pos; + if (this.baseParse) + this.baseParse.stopAt(pos); + else + for (let i = this.innerDone; i < this.inner.length; i++) + this.inner[i].parse.stopAt(pos); + } + startInner() { + let fragmentCursor = new FragmentCursor(this.fragments); + let overlay = null; + let covered = null; + let cursor = new TreeCursor(new TreeNode(this.baseTree, this.ranges[0].from, 0, null), 1 /* Full */); + scan: for (let nest, isCovered; this.stoppedAt == null || cursor.from < this.stoppedAt;) { + let enter = true, range; + if (fragmentCursor.hasNode(cursor)) { + if (overlay) { + let match = overlay.mounts.find(m => m.frag.from <= cursor.from && m.frag.to >= cursor.to && m.mount.overlay); + if (match) + for (let r of match.mount.overlay) { + let from = r.from + match.pos, to = r.to + match.pos; + if (from >= cursor.from && to <= cursor.to) + overlay.ranges.push({ from, to }); + } + } + enter = false; + } + else if (covered && (isCovered = checkCover(covered.ranges, cursor.from, cursor.to))) { + enter = isCovered != 2 /* Full */; + } + else if (!cursor.type.isAnonymous && cursor.from < cursor.to && (nest = this.nest(cursor, this.input))) { + if (!cursor.tree) + materialize(cursor); + let oldMounts = fragmentCursor.findMounts(cursor.from, nest.parser); + if (typeof nest.overlay == "function") { + overlay = new ActiveOverlay(nest.parser, nest.overlay, oldMounts, this.inner.length, cursor.from, cursor.tree, overlay); + } + else { + let ranges = punchRanges(this.ranges, nest.overlay || [new Range(cursor.from, cursor.to)]); + if (ranges.length) + this.inner.push(new InnerParse(nest.parser, nest.parser.startParse(this.input, enterFragments(oldMounts, ranges), ranges), nest.overlay ? nest.overlay.map(r => new Range(r.from - cursor.from, r.to - cursor.from)) : null, cursor.tree, ranges)); + if (!nest.overlay) + enter = false; + else if (ranges.length) + covered = { ranges, depth: 0, prev: covered }; + } + } + else if (overlay && (range = overlay.predicate(cursor))) { + if (range === true) + range = new Range(cursor.from, cursor.to); + if (range.from < range.to) + overlay.ranges.push(range); + } + if (enter && cursor.firstChild()) { + if (overlay) + overlay.depth++; + if (covered) + covered.depth++; + } + else { + for (;;) { + if (cursor.nextSibling()) + break; + if (!cursor.parent()) + break scan; + if (overlay && !--overlay.depth) { + let ranges = punchRanges(this.ranges, overlay.ranges); + if (ranges.length) + this.inner.splice(overlay.index, 0, new InnerParse(overlay.parser, overlay.parser.startParse(this.input, enterFragments(overlay.mounts, ranges), ranges), overlay.ranges.map(r => new Range(r.from - overlay.start, r.to - overlay.start)), overlay.target, ranges)); + overlay = overlay.prev; + } + if (covered && !--covered.depth) + covered = covered.prev; } } - if (dTop > 0 && dBottom > 0) - bias = Math.max(dTop, dBottom); - else if (dTop < 0 && dBottom < 0) - bias = Math.min(dTop, dBottom); - oracle.heightChanged = false; - this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(this.viewport.from, lineHeights)); - if (oracle.heightChanged) - result |= 2 /* Height */; } - let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) || - this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to); - if (viewportChange) - this.viewport = this.getViewport(bias, this.scrollTarget); - this.updateForViewport(); - if ((result & 2 /* Height */) || viewportChange) - this.updateViewportLines(); - if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */) - this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps)); - result |= this.computeVisibleRanges(); - if (this.mustEnforceCursorAssoc) { - this.mustEnforceCursorAssoc = false; - // This is done in the read stage, because moving the selection - // to a line end is going to trigger a layout anyway, so it - // can't be a pure write. It should be rare that it does any - // writing. - view.docView.enforceCursorAssoc(); + } +} +function checkCover(covered, from, to) { + for (let range of covered) { + if (range.from >= to) + break; + if (range.to > from) + return range.from <= from && range.to >= to ? 2 /* Full */ : 1 /* Partial */; + } + return 0 /* None */; +} +// Take a piece of buffer and convert it into a stand-alone +// TreeBuffer. +function sliceBuf(buf, startI, endI, nodes, positions, off) { + if (startI < endI) { + let from = buf.buffer[startI + 1], to = buf.buffer[endI - 2]; + nodes.push(buf.slice(startI, endI, from, to)); + positions.push(from - off); + } +} +// This function takes a node that's in a buffer, and converts it, and +// its parent buffer nodes, into a Tree. This is again acting on the +// assumption that the trees and buffers have been constructed by the +// parse that was ran via the mix parser, and thus aren't shared with +// any other code, making violations of the immutability safe. +function materialize(cursor) { + let { node } = cursor, depth = 0; + // Scan up to the nearest tree + do { + cursor.parent(); + depth++; + } while (!cursor.tree); + // Find the index of the buffer in that tree + let i = 0, base = cursor.tree, off = 0; + for (;; i++) { + off = base.positions[i] + cursor.from; + if (off <= node.from && off + base.children[i].length >= node.to) + break; + } + let buf = base.children[i], b = buf.buffer; + // Split a level in the buffer, putting the nodes before and after + // the child that contains `node` into new buffers. + function split(startI, endI, type, innerOffset, length) { + let i = startI; + while (b[i + 2] + off <= node.from) + i = b[i + 3]; + let children = [], positions = []; + sliceBuf(buf, startI, i, children, positions, innerOffset); + let from = b[i + 1], to = b[i + 2]; + let isTarget = from + off == node.from && to + off == node.to && b[i] == node.type.id; + children.push(isTarget ? node.toTree() : split(i + 4, b[i + 3], buf.set.types[b[i]], from, to - from)); + positions.push(from - innerOffset); + sliceBuf(buf, b[i + 3], endI, children, positions, innerOffset); + return new Tree(type, children, positions, length); + } + base.children[i] = split(0, b.length, NodeType.none, 0, buf.length); + // Move the cursor back to the target node + for (let d = 0; d <= depth; d++) + cursor.childAfter(node.from); +} +class StructureCursor { + constructor(root, offset) { + this.offset = offset; + this.done = false; + this.cursor = root.fullCursor(); + } + // Move to the first node (in pre-order) that starts at or after `pos`. + moveTo(pos) { + let { cursor } = this, p = pos - this.offset; + while (!this.done && cursor.from < p) { + if (cursor.to >= pos && cursor.enter(p, 1, false, false)) ; + else if (!cursor.next(false)) + this.done = true; } - return result; } - get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top); } - get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom); } - getViewport(bias, scrollTarget) { - // This will divide VP.Margin between the top and the - // bottom, depending on the bias (the change in viewport position - // since the last update). It'll hold a number between 0 and 1 - let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* Margin */ / 2)); - let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this; - let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).to); - // If scrollTarget is given, make sure the viewport includes that position - if (scrollTarget) { - let { head } = scrollTarget.range; - if (head < viewport.from || head > viewport.to) { - let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top); - let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos; - if (scrollTarget.y == "center") - topPos = (block.top + block.bottom) / 2 - viewHeight / 2; - else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from) - topPos = block.top; + hasNode(cursor) { + this.moveTo(cursor.from); + if (!this.done && this.cursor.from + this.offset == cursor.from && this.cursor.tree) { + for (let tree = this.cursor.tree;;) { + if (tree == cursor.tree) + return true; + if (tree.children.length && tree.positions[0] == 0 && tree.children[0] instanceof Tree) + tree = tree.children[0]; else - topPos = block.bottom - viewHeight; - viewport = new Viewport(map.lineAt(topPos - 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to); + break; } } - return viewport; + return false; } - mapViewport(viewport, changes) { - let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1); - return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0).to); +} +class FragmentCursor { + constructor(fragments) { + var _a; + this.fragments = fragments; + this.curTo = 0; + this.fragI = 0; + if (fragments.length) { + let first = this.curFrag = fragments[0]; + this.curTo = (_a = first.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : first.to; + this.inner = new StructureCursor(first.tree, -first.offset); + } + else { + this.curFrag = this.inner = null; + } } - // Checks if a given viewport covers the visible part of the - // document and not too much beyond that. - viewportIsAppropriate({ from, to }, bias = 0) { - if (!this.inView) - return true; - let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0); - let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0); - let { visibleTop, visibleBottom } = this; - return (from == 0 || top <= visibleTop - Math.max(10 /* MinCoverMargin */, Math.min(-bias, 250 /* MaxCoverMargin */))) && - (to == this.state.doc.length || - bottom >= visibleBottom + Math.max(10 /* MinCoverMargin */, Math.min(bias, 250 /* MaxCoverMargin */))) && - (top > visibleTop - 2 * 1000 /* Margin */ && bottom < visibleBottom + 2 * 1000 /* Margin */); + hasNode(node) { + while (this.curFrag && node.from >= this.curTo) + this.nextFrag(); + return this.curFrag && this.curFrag.from <= node.from && this.curTo >= node.to && this.inner.hasNode(node); } - mapLineGaps(gaps, changes) { - if (!gaps.length || changes.empty) - return gaps; - let mapped = []; - for (let gap of gaps) - if (!changes.touchesRange(gap.from, gap.to)) - mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size)); - return mapped; + nextFrag() { + var _a; + this.fragI++; + if (this.fragI == this.fragments.length) { + this.curFrag = this.inner = null; + } + else { + let frag = this.curFrag = this.fragments[this.fragI]; + this.curTo = (_a = frag.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : frag.to; + this.inner = new StructureCursor(frag.tree, -frag.offset); + } } - // Computes positions in the viewport where the start or end of a - // line should be hidden, trying to reuse existing line gaps when - // appropriate to avoid unneccesary redraws. - // Uses crude character-counting for the positioning and sizing, - // since actual DOM coordinates aren't always available and - // predictable. Relies on generous margins (see LG.Margin) to hide - // the artifacts this might produce from the user. - ensureLineGaps(current) { - let gaps = []; - // This won't work at all in predominantly right-to-left text. - if (this.heightOracle.direction != exports.Direction.LTR) - return gaps; - for (let line of this.viewportLines) { - if (line.length < 4000 /* DoubleMargin */) - continue; - let structure = lineStructure(line.from, line.to, this.state); - if (structure.total < 4000 /* DoubleMargin */) + findMounts(pos, parser) { + var _a; + let result = []; + if (this.inner) { + this.inner.cursor.moveTo(pos, 1); + for (let pos = this.inner.cursor.node; pos; pos = pos.parent) { + let mount = (_a = pos.tree) === null || _a === void 0 ? void 0 : _a.prop(NodeProp.mounted); + if (mount && mount.parser == parser) { + for (let i = this.fragI; i < this.fragments.length; i++) { + let frag = this.fragments[i]; + if (frag.from >= pos.to) + break; + if (frag.tree == this.curFrag.tree) + result.push({ + frag, + pos: pos.from - frag.offset, + mount + }); + } + } + } + } + return result; + } +} +function punchRanges(outer, ranges) { + let copy = null, current = ranges; + for (let i = 1, j = 0; i < outer.length; i++) { + let gapFrom = outer[i - 1].to, gapTo = outer[i].from; + for (; j < current.length; j++) { + let r = current[j]; + if (r.from >= gapTo) + break; + if (r.to <= gapFrom) continue; - let viewFrom, viewTo; - if (this.heightOracle.lineWrapping) { - let marginHeight = (2000 /* Margin */ / this.heightOracle.lineLength) * this.heightOracle.lineHeight; - viewFrom = findPosition(structure, (this.visibleTop - line.top - marginHeight) / line.height); - viewTo = findPosition(structure, (this.visibleBottom - line.top + marginHeight) / line.height); + if (!copy) + current = copy = ranges.slice(); + if (r.from < gapFrom) { + copy[j] = new Range(r.from, gapFrom); + if (r.to > gapTo) + copy.splice(j + 1, 0, new Range(gapTo, r.to)); + } + else if (r.to > gapTo) { + copy[j--] = new Range(gapTo, r.to); } else { - let totalWidth = structure.total * this.heightOracle.charWidth; - let marginWidth = 2000 /* Margin */ * this.heightOracle.charWidth; - viewFrom = findPosition(structure, (this.pixelViewport.left - marginWidth) / totalWidth); - viewTo = findPosition(structure, (this.pixelViewport.right + marginWidth) / totalWidth); + copy.splice(j--, 1); } - let outside = []; - if (viewFrom > line.from) - outside.push({ from: line.from, to: viewFrom }); - if (viewTo < line.to) - outside.push({ from: viewTo, to: line.to }); - let sel = this.state.selection.main; - // Make sure the gaps don't cover a selection end - if (sel.from >= line.from && sel.from <= line.to) - cutRange(outside, sel.from - 10 /* SelectionMargin */, sel.from + 10 /* SelectionMargin */); - if (!sel.empty && sel.to >= line.from && sel.to <= line.to) - cutRange(outside, sel.to - 10 /* SelectionMargin */, sel.to + 10 /* SelectionMargin */); - for (let { from, to } of outside) - if (to - from > 1000 /* HalfMargin */) { - gaps.push(find(current, gap => gap.from >= line.from && gap.to <= line.to && - Math.abs(gap.from - from) < 1000 /* HalfMargin */ && Math.abs(gap.to - to) < 1000 /* HalfMargin */) || - new LineGap(from, to, this.gapSize(line, from, to, structure))); - } } - return gaps; } - gapSize(line, from, to, structure) { - let fraction = findFraction(structure, to) - findFraction(structure, from); - if (this.heightOracle.lineWrapping) { - return line.height * fraction; + return current; +} +function findCoverChanges(a, b, from, to) { + let iA = 0, iB = 0, inA = false, inB = false, pos = -1e9; + let result = []; + for (;;) { + let nextA = iA == a.length ? 1e9 : inA ? a[iA].to : a[iA].from; + let nextB = iB == b.length ? 1e9 : inB ? b[iB].to : b[iB].from; + if (inA != inB) { + let start = Math.max(pos, from), end = Math.min(nextA, nextB, to); + if (start < end) + result.push(new Range(start, end)); } - else { - return structure.total * this.heightOracle.charWidth * fraction; + pos = Math.min(nextA, nextB); + if (pos == 1e9) + break; + if (nextA == pos) { + if (!inA) + inA = true; + else { + inA = false; + iA++; + } } - } - updateLineGaps(gaps) { - if (!LineGap.same(gaps, this.lineGaps)) { - this.lineGaps = gaps; - this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping))); + if (nextB == pos) { + if (!inB) + inB = true; + else { + inB = false; + iB++; + } } } - computeVisibleRanges() { - let deco = this.state.facet(decorations); - if (this.lineGaps.length) - deco = deco.concat(this.lineGapDeco); - let ranges = []; - rangeset.RangeSet.spans(deco, this.viewport.from, this.viewport.to, { - span(from, to) { ranges.push({ from, to }); }, - point() { } - }, 20); - let changed = ranges.length != this.visibleRanges.length || - this.visibleRanges.some((r, i) => r.from != ranges[i].from || r.to != ranges[i].to); - this.visibleRanges = ranges; - return changed ? 4 /* Viewport */ : 0; - } - lineBlockAt(pos) { - return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) || - scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler); - } - lineBlockAtHeight(height) { - return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler); - } - elementAtHeight(height) { - return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler); + return result; +} +// Given a number of fragments for the outer tree, and a set of ranges +// to parse, find fragments for inner trees mounted around those +// ranges, if any. +function enterFragments(mounts, ranges) { + let result = []; + for (let { pos, mount, frag } of mounts) { + let startPos = pos + (mount.overlay ? mount.overlay[0].from : 0), endPos = startPos + mount.tree.length; + let from = Math.max(frag.from, startPos), to = Math.min(frag.to, endPos); + if (mount.overlay) { + let overlay = mount.overlay.map(r => new Range(r.from + pos, r.to + pos)); + let changes = findCoverChanges(ranges, overlay, from, to); + for (let i = 0, pos = from;; i++) { + let last = i == changes.length, end = last ? to : changes[i].from; + if (end > pos) + result.push(new TreeFragment(pos, end, mount.tree, -startPos, frag.from >= pos, frag.to <= end)); + if (last) + break; + pos = changes[i].to; + } + } + else { + result.push(new TreeFragment(from, to, mount.tree, -startPos, frag.from >= startPos, frag.to <= endPos)); + } } - get docHeight() { - return this.scaler.toDOM(this.heightMap.height); + return result; +} + +exports.DefaultBufferLength = DefaultBufferLength; +exports.MountedTree = MountedTree; +exports.NodeProp = NodeProp; +exports.NodeSet = NodeSet; +exports.NodeType = NodeType; +exports.Parser = Parser; +exports.Tree = Tree; +exports.TreeBuffer = TreeBuffer; +exports.TreeCursor = TreeCursor; +exports.TreeFragment = TreeFragment; +exports.parseMixed = parseMixed; + +},{}],35:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var lr = require('@lezer/lr'); +var common = require('@lezer/common'); + +// This file was generated by lezer-generator. You probably shouldn't edit it. +const noSemi = 275, + incdec = 1, + incdecPrefix = 2, + templateContent = 276, + templateDollarBrace = 277, + templateEnd = 278, + insertSemi = 279, + TSExtends = 3, + spaces = 281, + newline = 282, + LineComment = 4, + BlockComment = 5, + Dialect_ts = 1; + +/* Hand-written tokenizers for JavaScript tokens that can't be + expressed by lezer's built-in tokenizer. */ + +const space = [9, 10, 11, 12, 13, 32, 133, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, + 8201, 8202, 8232, 8233, 8239, 8287, 12288]; + +const braceR = 125, braceL = 123, semicolon = 59, slash = 47, star = 42, + plus = 43, minus = 45, dollar = 36, backtick = 96, backslash = 92; + +const trackNewline = new lr.ContextTracker({ + start: false, + shift(context, term) { + return term == LineComment || term == BlockComment || term == spaces ? context : term == newline + }, + strict: false +}); + +const insertSemicolon = new lr.ExternalTokenizer((input, stack) => { + let {next} = input; + if ((next == braceR || next == -1 || stack.context) && stack.canShift(insertSemi)) + input.acceptToken(insertSemi); +}, {contextual: true, fallback: true}); + +const noSemicolon = new lr.ExternalTokenizer((input, stack) => { + let {next} = input, after; + if (space.indexOf(next) > -1) return + if (next == slash && ((after = input.peek(1)) == slash || after == star)) return + if (next != braceR && next != semicolon && next != -1 && !stack.context && stack.canShift(noSemi)) + input.acceptToken(noSemi); +}, {contextual: true}); + +const incdecToken = new lr.ExternalTokenizer((input, stack) => { + let {next} = input; + if (next == plus || next == minus) { + input.advance(); + if (next == input.next) { + input.advance(); + let mayPostfix = !stack.context && stack.canShift(incdec); + input.acceptToken(mayPostfix ? incdec : incdecPrefix); } - get contentHeight() { - return this.docHeight + this.paddingTop + this.paddingBottom; + } +}, {contextual: true}); + +const template = new lr.ExternalTokenizer(input => { + for (let afterDollar = false, i = 0;; i++) { + let {next} = input; + if (next < 0) { + if (i) input.acceptToken(templateContent); + break + } else if (next == backtick) { + if (i) input.acceptToken(templateContent); + else input.acceptToken(templateEnd, 1); + break + } else if (next == braceL && afterDollar) { + if (i == 1) input.acceptToken(templateDollarBrace, 1); + else input.acceptToken(templateContent, -1); + break + } else if (next == 10 /* "\n" */ && i) { + // Break up template strings on lines, to avoid huge tokens + input.advance(); + input.acceptToken(templateContent); + break + } else if (next == backslash) { + input.advance(); } + afterDollar = next == dollar; + input.advance(); + } +}); + +function tsExtends(value, stack) { + return value == "extends" && stack.dialectEnabled(Dialect_ts) ? TSExtends : -1 } -class Viewport { - constructor(from, to) { - this.from = from; - this.to = to; + +// This file was generated by lezer-generator. You probably shouldn't edit it. +const spec_identifier = {__proto__:null,export:16, as:21, from:25, default:30, async:35, function:36, this:46, true:54, false:54, void:60, typeof:64, null:78, super:80, new:114, await:131, yield:133, delete:134, class:144, extends:146, public:189, private:189, protected:189, readonly:191, instanceof:212, in:214, const:216, import:248, keyof:299, unique:303, infer:309, is:343, abstract:363, implements:365, type:367, let:370, var:372, interface:379, enum:383, namespace:389, module:391, declare:395, global:399, for:420, of:429, while:432, with:436, do:440, if:444, else:446, switch:450, case:456, try:462, catch:464, finally:466, return:470, throw:474, break:478, continue:482, debugger:486}; +const spec_word = {__proto__:null,async:101, get:103, set:105, public:153, private:153, protected:153, static:155, abstract:157, override:159, readonly:165, new:347}; +const spec_LessThan = {__proto__:null,"<":121}; +const parser = lr.LRParser.deserialize({ + version: 13, + states: "$1WO`QYOOO'QQ!LdO'#CgO'XOSO'#DSO)dQYO'#DXO)tQYO'#DdO){QYO'#DnO-xQYO'#DtOOQO'#EX'#EXO.]QWO'#EWO.bQWO'#EWOOQ!LS'#Eb'#EbO0aQ!LdO'#IqO2wQ!LdO'#IrO3eQWO'#EvO3jQpO'#F]OOQ!LS'#FO'#FOO3rO!bO'#FOO4QQWO'#FdO5_QWO'#FcOOQ!LS'#Ir'#IrOOQ!LQ'#Iq'#IqOOQQ'#J['#J[O5dQWO'#HjO5iQ!LYO'#HkOOQQ'#Ic'#IcOOQQ'#Hl'#HlQ`QYOOO){QYO'#DfO5qQWO'#GWO5vQ#tO'#ClO6UQWO'#EVO6aQWO'#EcO6fQ#tO'#E}O7QQWO'#GWO7VQWO'#G[O7bQWO'#G[O7pQWO'#G_O7pQWO'#G`O7pQWO'#GbO5qQWO'#GeO8aQWO'#GhO9oQWO'#CcO:PQWO'#GuO:XQWO'#G{O:XQWO'#G}O`QYO'#HPO:XQWO'#HRO:XQWO'#HUO:^QWO'#H[O:cQ!LZO'#H`O){QYO'#HbO:nQ!LZO'#HdO:yQ!LZO'#HfO5iQ!LYO'#HhO){QYO'#IsOOOS'#Hn'#HnO;UOSO,59nOOQ!LS,59n,59nO=gQbO'#CgO=qQYO'#HoO>OQWO'#ItO?}QbO'#ItO'dQYO'#ItO@UQWO,59sO@lQ&jO'#D^OAeQWO'#EXOArQWO'#JPOA}QWO'#JOOBVQWO,5:uOB[QWO'#I}OBcQWO'#DuO5vQ#tO'#EVOBqQWO'#EVOB|Q`O'#E}OOQ!LS,5:O,5:OOCUQYO,5:OOESQ!LdO,5:YOEpQWO,5:`OFZQ!LYO'#I|O7VQWO'#I{OFbQWO'#I{OFjQWO,5:tOFoQWO'#I{OF}QYO,5:rOH}QWO'#ESOJXQWO,5:rOKhQWO'#DhOKoQYO'#DmOKyQ&jO,5:{O){QYO,5:{OOQQ'#En'#EnOOQQ'#Ep'#EpO){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}O){QYO,5:}OOQQ'#Et'#EtOLRQYO,5;_OOQ!LS,5;d,5;dOOQ!LS,5;e,5;eONRQWO,5;eOOQ!LS,5;f,5;fO){QYO'#HyONWQ!LYO,5UOOQQ'#If'#IfOOQQ,5>V,5>VOOQQ-E;j-E;jO!+SQ!LdO,5:QOOQ!LQ'#Co'#CoO!+sQ#tO,5O,5>OO!7yQWO,5>OOOQQ,5>Q,5>QO!7yQWO,5>QOOQQ,5>S,5>SO!8OQ`O,5?_OOOS-E;l-E;lOOQ!LS1G/Y1G/YO!8TQbO,5>ZO){QYO,5>ZOOQO-E;m-E;mO!8_QWO,5?`O!8gQbO,5?`O!8nQWO,5?jOOQ!LS1G/_1G/_O!8vQpO'#DQOOQO'#Iv'#IvO){QYO'#IvO!9eQpO'#IvO!:SQpO'#D_O!:eQ&jO'#D_O!SQ&jO'#D_O){QYO,5?kO!>^QWO'#HtO!8nQWO,5?jOOQ!LQ1G0a1G0aO!?jQ&jO'#DxOOQ!LS,5:a,5:aO){QYO,5:aOH}QWO,5:aO!?qQWO,5:aO:^QWO,5:qO!,lQpO,5:qO!,tQ#tO,5:qO5vQ#tO,5:qOOQ!LS1G/j1G/jOOQ!LS1G/z1G/zOOQ!LQ'#ER'#ERO){QYO,5?hO!?|Q!LYO,5?hO!@_Q!LYO,5?hO!@fQWO,5?gO!@nQWO'#HvO!@fQWO,5?gOOQ!LQ1G0`1G0`O7VQWO,5?gOOQ!LS1G0^1G0^O!AYQ!LdO1G0^O!AyQ!LbO,5:nOOQ!LS'#Fm'#FmO!BgQ!LdO'#IlOF}QYO1G0^O!DfQ#tO'#IwO!DpQWO,5:SO!DuQbO'#IxO){QYO'#IxO!EPQWO,5:XOOQ!LS'#DQ'#DQOOQ!LS1G0g1G0gO!EUQWO1G0gO!GgQ!LdO1G0iO!GnQ!LdO1G0iO!JRQ!LdO1G0iO!JYQ!LdO1G0iO!LaQ!LdO1G0iO!LtQ!LdO1G0iO# eQ!LdO1G0iO# lQ!LdO1G0iO#$PQ!LdO1G0iO#$WQ!LdO1G0iO#%{Q!LdO1G0iO#(uQ7^O'#CgO#*pQ7^O1G0yO#,kQ7^O'#IrOOQ!LS1G1P1G1PO#-OQ!LdO,5>eOOQ!LQ-E;w-E;wO#-oQ!LdO1G0iOOQ!LS1G0i1G0iO#/qQ!LdO1G0|O#0bQpO,5;oO#0gQpO,5;pO#0lQpO'#FWO#1QQWO'#FVOOQO'#JU'#JUOOQO'#Hw'#HwO#1VQpO1G1XOOQ!LS1G1X1G1XOOOO1G1b1G1bO#1eQ7^O'#IqO#1oQWO,5;yOLRQYO,5;yOOOO-E;v-E;vOOQ!LS1G1U1G1UOOQ!LS,5;{,5;{O#1tQpO,5;{OOQ!LS,59`,59`OH}QWO'#InOOOS'#Hm'#HmO#1yOSO,59dOOQ!LS,59d,59dO){QYO1G1hO!(eQWO'#H{O#2UQWO,5SQWO'#J_O#>_QWO,5=[OOQQ1G.i1G.iO#>dQ!LYO1G.iO#>oQWO1G.iO!(ZQWO1G.iO5iQ!LYO1G.iO#>tQbO,5?|O#?OQWO,5?|O#?ZQYO,5=cO#?bQWO,5=cO7VQWO,5?|OOQQ1G2{1G2{O`QYO1G2{OOQQ1G3R1G3ROOQQ1G3T1G3TO:XQWO1G3VO#?gQYO1G3XO#CbQYO'#HWOOQQ1G3[1G3[O:^QWO1G3bO#CoQWO1G3bO5iQ!LYO1G3fOOQQ1G3h1G3hOOQ!LQ'#Ft'#FtO5iQ!LYO1G3jO5iQ!LYO1G3lOOOS1G4y1G4yO#CwQ`O,5`,5>`O7VQWO,5>`OOQO-E;r-E;rOOQ!LQ'#EO'#EOO#FbQ!LrO'#EPO!?bQ&jO'#DyOOQO'#Hs'#HsO#F|Q&jO,5:dOOQ!LS,5:d,5:dO#GTQ&jO'#DyO#GfQ&jO'#DyO#GmQ&jO'#EUO#GpQ&jO'#EPO#G}Q&jO'#EPO!?bQ&jO'#EPO#HbQWO1G/{O#HgQ`O1G/{OOQ!LS1G/{1G/{O){QYO1G/{OH}QWO1G/{OOQ!LS1G0]1G0]O:^QWO1G0]O!,lQpO1G0]O!,tQ#tO1G0]O#HnQ!LdO1G5SO){QYO1G5SO#IOQ!LYO1G5SO#IaQWO1G5RO7VQWO,5>bOOQO,5>b,5>bO#IiQWO,5>bOOQO-E;t-E;tO#IaQWO1G5RO#IwQ!LdO,59gO#KvQ!LdO,5g,5>gO$'gQWO,5>gOOQ!LS1G1{1G1{P$'lQWO'#H{POQ!LS-E;y-E;yO$(]Q#tO1G2WO$)OQ#tO1G2YO$)YQ#tO1G2[OOQ!LS1G1t1G1tO$)aQWO'#HzO$)oQWO,5?sO$)oQWO,5?sO$)wQWO,5?sO$*SQWO,5?sOOQO1G1v1G1vO$*bQ#tO1G1uO$*rQWO'#H|O$+SQWO,5?tOH}QWO,5?tO$+[Q`O,5?tOOQ!LS1G1y1G1yO5iQ!LYO,5j,5>jOOQO-E;|-E;|O!-lQ&jO,59iO){QYO,59iO$,gQWO1G1pOJ^QWO1G1wO$,lQ!LdO7+'TOOQ!LS7+'T7+'TOF}QYO7+'TOOQ!LS7+%W7+%WO$-]Q`O'#JZO#HbQWO7+'xO$-gQWO7+'xO$-oQ`O7+'xOOQQ7+'x7+'xOH}QWO7+'xO){QYO7+'xOH}QWO7+'xOOQO1G.v1G.vO$-yQ!LbO'#CgO$.ZQ!LbO,5r,5>rOOQO-El,5>lOOQ!LQ-En,5>nOOQO-E[,5>[OOQO-E;n-E;nOOQO,5>a,5>aOOQO-E;s-E;sO!,lQpO1G/eOOQO1G3z1G3zO:^QWO,5:eOOQO,5:k,5:kO){QYO,5:kO$8tQ!LYO,5:kO$9PQ!LYO,5:kO!,lQpO,5:eOOQO-E;q-E;qOOQ!LS1G0O1G0OO!?bQ&jO,5:eO$9_Q&jO,5:eO$9pQ!LrO,5:kO$:[Q&jO,5:eO!?bQ&jO,5:kOOQO,5:p,5:pO$:cQ&jO,5:kO$:pQ!LYO,5:kOOQ!LS7+%g7+%gO#HbQWO7+%gO#HgQ`O7+%gOOQ!LS7+%w7+%wO:^QWO7+%wO!,lQpO7+%wO$;UQ!LdO7+*nO){QYO7+*nOOQO1G3|1G3|O7VQWO1G3|O$;fQWO7+*mO$;nQ!LdO1G2WO$=pQ!LdO1G2YO$?rQ!LdO1G1uO$AzQ#tO,5>]OOQO-E;o-E;oO$BUQbO,5>^O){QYO,5>^OOQO-E;p-E;pO$B`QWO1G5OO$BhQ7^O1G0^O$DoQ7^O1G0iO$DvQ7^O1G0iO$FwQ7^O1G0iO$GOQ7^O1G0iO$HsQ7^O1G0iO$IWQ7^O1G0iO$KeQ7^O1G0iO$KlQ7^O1G0iO$MmQ7^O1G0iO$MtQ7^O1G0iO% iQ7^O1G0iO% |Q!LdO<eOOOO7+'P7+'POOOS1G4t1G4tOOQ!LS1G4R1G4ROJ^QWO7+'vO%&vQWO,5>fO5qQWO,5>fOOQO-E;x-E;xO%'UQWO1G5_O%'UQWO1G5_O%'^QWO1G5_O%'iQ`O,5>hO%'sQWO,5>hOH}QWO,5>hOOQO-E;z-E;zO%'xQ`O1G5`O%(SQWO1G5`OOQO1G2O1G2OOOQO1G2P1G2PO5iQ!LYO1G2PO$+fQWO1G2PO5iQ!LYO1G2OO%([QWO1G2QOH}QWO1G2QOOQO1G2R1G2RO5iQ!LYO1G2UO!,lQpO1G2OO#4jQWO1G2PO%(aQWO1G2QO%(iQWO1G2POJ^QWO7+*]OOQ!LS1G/T1G/TO%(tQWO1G/TOOQ!LS7+'[7+'[O%(yQ#tO7+'cO%)ZQ!LdO<q,5>qO%+VQWO,5>qO#;kQWO,5>qOOQO-EpOOQO-EQQ`O1G4SO%>[QWO7+*zOOQO7+'k7+'kO5iQ!LYO7+'kOOQO7+'j7+'jO$+fQWO7+'lO%>dQ`O7+'lOOQO7+'p7+'pO5iQ!LYO7+'jO$+fQWO7+'kO%>kQWO7+'lOH}QWO7+'lO#4jQWO7+'kO%>pQ#tO<zQ`O,5>kOOQO-E;}-E;}O#HbQWOANAOOOQQANAOANAOOH}QWOANAOO%?UQ!LbO7+'nOOQQAN=dAN=dO5qQWO1G4]OOQO1G4]1G4]O%?cQWO1G4]O%?hQWO7++RO%?hQWO7++RO5iQ!LYOANAkO%?pQWOANAkOOQQANAkANAkO%?uQWOANAOO%?}Q`OANAOOOQQANAVANAVOOQQANAWANAWO%@XQWO,5>mOOQO-E}AN>}O%C|Q!LdO<wAN>wOOQOAN>qAN>qO%/yQ!LdOAN>wO:^QWOAN>qO){QYOAN>wO!,lQpOAN>qO&&xQ!LYOAN>wO&'TQ7^O<WOz%{O~Ou&OO!S&YO!T&RO!U&RO'X$aO~O]&POj&PO|&SO'd%|O!O'iP!O'tP~P@ZOz'qX}'qX!X'qX!_'qX'n'qX~O!w'qX#S!{X!O'qX~PASO!w&ZOz'sX}'sX~O}&[Oz'rX~Oz&^O~O!w#dO~PASOR&bO!P&_O!k&aO'W$_O~Ob&gO!`$WO'W$_O~Or$mO!`$lO~O!O&hO~P`Or!zOs!zOu!{O!^!xO!`!yO'aQOP!baY!bai!ba}!ba!]!ba!f!ba#W!ba#X!ba#Y!ba#Z!ba#[!ba#]!ba#^!ba#_!ba#a!ba#c!ba#e!ba#f!ba'n!ba'u!ba'v!ba~O^!ba'R!baz!ba!_!ba'c!ba!P!ba$|!ba!X!ba~PC]O!_&iO~O!X!vO!w&kO'n&jO}'pX^'pX'R'pX~O!_'pX~PEuO}&oO!_'oX~O!_&qO~Ou$sO!P$tO#R&rO'W$_O~OPTOQTO]cOa!jOb!iOgcOiTOjcOkcOnTOpTOuROwcOxcOycO!PSO!ZkO!`UO!cTO!dTO!eTO!fTO!gTO!j!hO#p!kO#t^O'W9VO'aQO'mYO'zaO~O]#pOg#}Oi#qOj#pOk#pOn$OOp9iOu#wO!P#xO!Z:lO!`#uO#R9oO#p$SO$Z9kO$]9mO$`$TO'W&vO'a#rO~O#S&xO~O]#pOg#}Oi#qOj#pOk#pOn$OOp$POu#wO!P#xO!Z$UO!`#uO#R$VO#p$SO$Z$QO$]$RO$`$TO'W&vO'a#rO~O'['kP~PJ^O|&|O!_'lP~P){O'd'OO'mYO~OP9SOQ9SO]cOa:jOb!iOgcOi9SOjcOkcOn9SOp9SOuROwcOxcOycO!P!bO!Z9UO!`UO!c9SO!d9SO!e9SO!f9SO!g9SO!j!hO#p!kO#t^O'W'^O'aQO'mYO'z:hO~O!`!yO~O}#aO^$Xa'R$Xa!_$Xaz$Xa!P$Xa$|$Xa!X$Xa~O#`'eO~PH}O!X'gO!P'wX#s'wX#v'wX#}'wX~Or'hO~PNyOr'hO!P'wX#s'wX#v'wX#}'wX~O!P'jO#s'nO#v'iO#}'oO~O|'rO~PLRO#v#eO#}'uO~Or$aXu$aX!^$aX'n$aX'u$aX'v$aX~OReX}eX!weX'[eX'[$aX~P!!cOj'wO~O'O'yO'P'xO'Q'{O~Or'}Ou(OO'n#ZO'u(QO'v(SO~O'['|O~P!#lO'[(VO~O]#pOg#}Oi#qOj#pOk#pOn$OOp9iOu#wO!P#xO!Z:lO!`#uO#R9oO#p$SO$Z9kO$]9mO$`$TO'a#rO~O|(ZO'W(WO!_'{P~P!$ZO#S(]O~O|(aO'W(^Oz'|P~P!$ZO^(jOi(oOu(gO!S(mO!T(fO!U(fO!`(dO!t(nO$s(iO'X$aO'd(cO~O!O(lO~P!&RO!^!xOr'`Xu'`X'n'`X'u'`X'v'`X}'`X!w'`X~O'['`X#i'`X~P!&}OR(rO!w(qO}'_X'['_X~O}(sO'['^X~O'W(uO~O!`(zO~O'W&vO~O!`(dO~Ou$sO|!qO!P$tO#Q!tO#R!qO'W$_O!_'oP~O!X!vO#S)OO~OP#]OY#cOi#QOr!zOs!zOu!{O!]#SO!^!xO!`!yO!f#]O#W#OO#X#PO#Y#PO#Z#PO#[#RO#]#SO#^#SO#_#SO#a#TO#c#VO#e#XO#f#YO'aQO'n#ZO'u!|O'v!}O~O^!Ya}!Ya'R!Yaz!Ya!_!Ya'c!Ya!P!Ya$|!Ya!X!Ya~P!)`OR)WO!P&_O!k)VO$|)UO']$bO~O'W$yO'['^P~O!X)ZO!P'ZX^'ZX'R'ZX~O!`$WO']$bO~O!`$WO'W$_O']$bO~O!X!vO#S&xO~O$})gO'W)cO!O(TP~O})hO[(SX~O'd'OO~OY)lO~O[)mO~O!P$jO'W$_O'X$aO[(SP~Ou$sO|)rO!P$tO'W$_Oz'rP~O]&VOj&VO|)sO'd'OO!O'tP~O})tO^(PX'R(PX~O!w)xO']$bO~OR){O!P#xO']$bO~O!P)}O~Or*PO!PSO~O!j*UO~Ob*ZO~O'W(uO!O(RP~Ob$hO~O$}tO'W$yO~P8tOY*aO[*`O~OPTOQTO]cOanObmOgcOiTOjcOkcOnTOpTOuROwcOxcOycO!ZkO!`UO!cTO!dTO!eTO!fTO!gTO!jlO#t^O${qO'aQO'mYO'zaO~O!P!bO#p!kO'W9VO~P!0uO[*`O^$ZO'R$ZO~O^*eO#`*gO%P*gO%Q*gO~P){O!`%^O~O%p*lO~O!P*nO~O&Q*qO&R*pOP&OaQ&OaW&Oa]&Oa^&Oaa&Oab&Oag&Oai&Oaj&Oak&Oan&Oap&Oau&Oaw&Oax&Oay&Oa!P&Oa!Z&Oa!`&Oa!c&Oa!d&Oa!e&Oa!f&Oa!g&Oa!j&Oa#`&Oa#p&Oa#t&Oa${&Oa$}&Oa%P&Oa%Q&Oa%T&Oa%V&Oa%Y&Oa%Z&Oa%]&Oa%j&Oa%p&Oa%r&Oa%t&Oa%v&Oa%y&Oa&P&Oa&T&Oa&V&Oa&X&Oa&Z&Oa&]&Oa&|&Oa'W&Oa'a&Oa'm&Oa'z&Oa!O&Oa%w&Oa_&Oa%|&Oa~O'W*tO~O'c*wO~Oz&ca}&ca~P!)`O}!]Oz'ha~Oz'ha~P>WO}&[Oz'ra~O}tX}!VX!OtX!O!VX!XtX!X!VX!`!VX!wtX']!VX~O!X+OO!w*}O}#PX}'jX!O#PX!O'jX!X'jX!`'jX']'jX~O!X+QO!`$WO']$bO}!RX!O!RX~O]%}Oj%}Ou&OO'd(cO~OP9SOQ9SO]cOa:jOb!iOgcOi9SOjcOkcOn9SOp9SOuROwcOxcOycO!P!bO!Z9UO!`UO!c9SO!d9SO!e9SO!f9SO!g9SO!j!hO#p!kO#t^O'aQO'mYO'z:hO~O'W9sO~P!:sO}+UO!O'iX~O!O+WO~O!X+OO!w*}O}#PX!O#PX~O}+XO!O'tX~O!O+ZO~O]%}Oj%}Ou&OO'X$aO'd(cO~O!T+[O!U+[O~P!=qOu$sO|+_O!P$tO'W$_Oz&hX}&hX~O^+dO!S+gO!T+cO!U+cO!n+kO!o+iO!p+jO!q+hO!t+lO'X$aO'd(cO'm+aO~O!O+fO~P!>rOR+qO!P&_O!k+pO~O!w+wO}'pa!_'pa^'pa'R'pa~O!X!vO~P!?|O}&oO!_'oa~Ou$sO|+zO!P$tO#Q+|O#R+zO'W$_O}&jX!_&jX~O^!zi}!zi'R!ziz!zi!_!zi'c!zi!P!zi$|!zi!X!zi~P!)`O#S!va}!va!_!va!w!va!P!va^!va'R!vaz!va~P!#lO#S'`XP'`XY'`X^'`Xi'`Xs'`X!]'`X!`'`X!f'`X#W'`X#X'`X#Y'`X#Z'`X#['`X#]'`X#^'`X#_'`X#a'`X#c'`X#e'`X#f'`X'R'`X'a'`X!_'`Xz'`X!P'`X'c'`X$|'`X!X'`X~P!&}O},VO'['kX~P!#lO'[,XO~O},YO!_'lX~P!)`O!_,]O~Oz,^O~OP#]Or!zOs!zOu!{O!^!xO!`!yO!f#]O'aQOY#Vi^#Vii#Vi}#Vi!]#Vi#X#Vi#Y#Vi#Z#Vi#[#Vi#]#Vi#^#Vi#_#Vi#a#Vi#c#Vi#e#Vi#f#Vi'R#Vi'n#Vi'u#Vi'v#Viz#Vi!_#Vi'c#Vi!P#Vi$|#Vi!X#Vi~O#W#Vi~P!EZO#W#OO~P!EZOP#]Or!zOs!zOu!{O!^!xO!`!yO!f#]O#W#OO#X#PO#Y#PO#Z#PO'aQOY#Vi^#Vi}#Vi!]#Vi#[#Vi#]#Vi#^#Vi#_#Vi#a#Vi#c#Vi#e#Vi#f#Vi'R#Vi'n#Vi'u#Vi'v#Viz#Vi!_#Vi'c#Vi!P#Vi$|#Vi!X#Vi~Oi#Vi~P!GuOi#QO~P!GuOP#]Oi#QOr!zOs!zOu!{O!^!xO!`!yO!f#]O#W#OO#X#PO#Y#PO#Z#PO#[#RO'aQO^#Vi}#Vi#a#Vi#c#Vi#e#Vi#f#Vi'R#Vi'n#Vi'u#Vi'v#Viz#Vi!_#Vi'c#Vi!P#Vi$|#Vi!X#Vi~OY#Vi!]#Vi#]#Vi#^#Vi#_#Vi~P!JaOY#cO!]#SO#]#SO#^#SO#_#SO~P!JaOP#]OY#cOi#QOr!zOs!zOu!{O!]#SO!^!xO!`!yO!f#]O#W#OO#X#PO#Y#PO#Z#PO#[#RO#]#SO#^#SO#_#SO#a#TO'aQO^#Vi}#Vi#c#Vi#e#Vi#f#Vi'R#Vi'n#Vi'v#Viz#Vi!_#Vi'c#Vi!P#Vi$|#Vi!X#Vi~O'u#Vi~P!MXO'u!|O~P!MXOP#]OY#cOi#QOr!zOs!zOu!{O!]#SO!^!xO!`!yO!f#]O#W#OO#X#PO#Y#PO#Z#PO#[#RO#]#SO#^#SO#_#SO#a#TO#c#VO'aQO'u!|O^#Vi}#Vi#e#Vi#f#Vi'R#Vi'n#Viz#Vi!_#Vi'c#Vi!P#Vi$|#Vi!X#Vi~O'v#Vi~P# sO'v!}O~P# sOP#]OY#cOi#QOr!zOs!zOu!{O!]#SO!^!xO!`!yO!f#]O#W#OO#X#PO#Y#PO#Z#PO#[#RO#]#SO#^#SO#_#SO#a#TO#c#VO#e#XO'aQO'u!|O'v!}O~O^#Vi}#Vi#f#Vi'R#Vi'n#Viz#Vi!_#Vi'c#Vi!P#Vi$|#Vi!X#Vi~P#$_OPZXYZXiZXrZXsZXuZX!]ZX!^ZX!`ZX!fZX!wZX#ScX#WZX#XZX#YZX#ZZX#[ZX#]ZX#^ZX#_ZX#aZX#cZX#eZX#fZX#kZX'aZX'nZX'uZX'vZX}ZX!OZX~O#iZX~P#&rOP#]OY9gOi9[Or!zOs!zOu!{O!]9^O!^!xO!`!yO!f#]O#W9YO#X9ZO#Y9ZO#Z9ZO#[9]O#]9^O#^9^O#_9^O#a9_O#c9aO#e9cO#f9dO'aQO'n#ZO'u!|O'v!}O~O#i,`O~P#(|OP'fXY'fXi'fXr'fXs'fXu'fX!]'fX!^'fX!`'fX!f'fX#W'fX#X'fX#Y'fX#Z'fX#['fX#]'fX#^'fX#a'fX#c'fX#e'fX#f'fX'a'fX'n'fX'u'fX'v'fX}'fX~O!w9hO#k9hO#_'fX#i'fX!O'fX~P#*wO^&ma}&ma'R&ma!_&ma'c&maz&ma!P&ma$|&ma!X&ma~P!)`OP#ViY#Vi^#Vii#Vis#Vi}#Vi!]#Vi!^#Vi!`#Vi!f#Vi#W#Vi#X#Vi#Y#Vi#Z#Vi#[#Vi#]#Vi#^#Vi#_#Vi#a#Vi#c#Vi#e#Vi#f#Vi'R#Vi'a#Viz#Vi!_#Vi'c#Vi!P#Vi$|#Vi!X#Vi~P!#lO^#ji}#ji'R#jiz#ji!_#ji'c#ji!P#ji$|#ji!X#ji~P!)`O#v,bO~O#v,cO~O!X'gO!w,dO!P#zX#s#zX#v#zX#}#zX~O|,eO~O!P'jO#s,gO#v'iO#},hO~O}9eO!O'eX~P#(|O!O,iO~O#},kO~O'O'yO'P'xO'Q,nO~O],qOj,qOz,rO~O}cX!XcX!_cX!_$aX'ncX~P!!cO!_,xO~P!#lO},yO!X!vO'n&jO!_'{X~O!_-OO~Oz$aX}$aX!X$hX~P!!cO}-QOz'|X~P!#lO!X-SO~Oz-UO~O|(ZO'W$_O!_'{P~Oi-YO!X!vO!`$WO']$bO'n&jO~O!X)ZO~O!O-`O~P!&RO!T-aO!U-aO'X$aO'd(cO~Ou-cO'd(cO~O!t-dO~O'W$yO}&rX'[&rX~O}(sO'['^a~Or-iOs-iOu-jO'noa'uoa'voa}oa!woa~O'[oa#ioa~P#5{Or'}Ou(OO'n$Ya'u$Ya'v$Ya}$Ya!w$Ya~O'[$Ya#i$Ya~P#6qOr'}Ou(OO'n$[a'u$[a'v$[a}$[a!w$[a~O'[$[a#i$[a~P#7dO]-kO~O#S-lO~O'[$ja}$ja#i$ja!w$ja~P!#lO#S-oO~OR-xO!P&_O!k-wO$|-vO~O'[-yO~O]#pOi#qOj#pOk#pOn$OOp9iOu#wO!P#xO!Z:lO!`#uO#R9oO#p$SO$Z9kO$]9mO$`$TO'a#rO~Og-{O'W-zO~P#9ZO!X)ZO!P'Za^'Za'R'Za~O#S.RO~OYZX}cX!OcX~O}.SO!O(TX~O!O.UO~OY.VO~O'W)cO~O!P$jO'W$_O[&zX}&zX~O})hO[(Sa~O!_.[O~P!)`O].^O~OY._O~O[.`O~OR-xO!P&_O!k-wO$|-vO']$bO~O})tO^(Pa'R(Pa~O!w.fO~OR.iO!P#xO~O'd'OO!O(QP~OR.sO!P.oO!k.rO$|.qO']$bO~OY.}O}.{O!O(RX~O!O/OO~O[/QO^$ZO'R$ZO~O]/RO~O#_/TO%n/UO~P0zO!w#dO#_/TO%n/UO~O^/VO~P){O^/XO~O%w/]OP%uiQ%uiW%ui]%ui^%uia%uib%uig%uii%uij%uik%uin%uip%uiu%uiw%uix%uiy%ui!P%ui!Z%ui!`%ui!c%ui!d%ui!e%ui!f%ui!g%ui!j%ui#`%ui#p%ui#t%ui${%ui$}%ui%P%ui%Q%ui%T%ui%V%ui%Y%ui%Z%ui%]%ui%j%ui%p%ui%r%ui%t%ui%v%ui%y%ui&P%ui&T%ui&V%ui&X%ui&Z%ui&]%ui&|%ui'W%ui'a%ui'm%ui'z%ui!O%ui_%ui%|%ui~O_/cO!O/aO%|/bO~P`O!PSO!`/fO~O}#aO'c$Xa~Oz&ci}&ci~P!)`O}!]Oz'hi~O}&[Oz'ri~Oz/jO~O}!Ra!O!Ra~P#(|O]%}Oj%}O|/pO'd(cO}&dX!O&dX~P@ZO}+UO!O'ia~O]&VOj&VO|)sO'd'OO}&iX!O&iX~O}+XO!O'ta~Oz'si}'si~P!)`O^$ZO!X!vO!`$WO!f/{O!w/yO'R$ZO']$bO'n&jO~O!O0OO~P!>rO!T0PO!U0PO'X$aO'd(cO'm+aO~O!S0QO~P#GTO!PSO!S0QO!q0SO!t0TO~P#GTO!S0QO!o0VO!p0VO!q0SO!t0TO~P#GTO!P&_O~O!P&_O~P!#lO}'pi!_'pi^'pi'R'pi~P!)`O!w0`O}'pi!_'pi^'pi'R'pi~O}&oO!_'oi~Ou$sO!P$tO#R0bO'W$_O~O#SoaPoaYoa^oaioa!]oa!^oa!`oa!foa#Woa#Xoa#Yoa#Zoa#[oa#]oa#^oa#_oa#aoa#coa#eoa#foa'Roa'aoa!_oazoa!Poa'coa$|oa!Xoa~P#5{O#S$YaP$YaY$Ya^$Yai$Yas$Ya!]$Ya!^$Ya!`$Ya!f$Ya#W$Ya#X$Ya#Y$Ya#Z$Ya#[$Ya#]$Ya#^$Ya#_$Ya#a$Ya#c$Ya#e$Ya#f$Ya'R$Ya'a$Ya!_$Yaz$Ya!P$Ya'c$Ya$|$Ya!X$Ya~P#6qO#S$[aP$[aY$[a^$[ai$[as$[a!]$[a!^$[a!`$[a!f$[a#W$[a#X$[a#Y$[a#Z$[a#[$[a#]$[a#^$[a#_$[a#a$[a#c$[a#e$[a#f$[a'R$[a'a$[a!_$[az$[a!P$[a'c$[a$|$[a!X$[a~P#7dO#S$jaP$jaY$ja^$jai$jas$ja}$ja!]$ja!^$ja!`$ja!f$ja#W$ja#X$ja#Y$ja#Z$ja#[$ja#]$ja#^$ja#_$ja#a$ja#c$ja#e$ja#f$ja'R$ja'a$ja!_$jaz$ja!P$ja!w$ja'c$ja$|$ja!X$ja~P!#lO^!zq}!zq'R!zqz!zq!_!zq'c!zq!P!zq$|!zq!X!zq~P!)`O}&eX'[&eX~PJ^O},VO'['ka~O|0jO}&fX!_&fX~P){O},YO!_'la~O},YO!_'la~P!)`O#i!ba!O!ba~PC]O#i!Ya}!Ya!O!Ya~P#(|O!P0}O#t^O#{1OO~O!O1SO~O'c1TO~P!#lO^$Uq}$Uq'R$Uqz$Uq!_$Uq'c$Uq!P$Uq$|$Uq!X$Uq~P!)`Oz1UO~O],qOj,qO~Or'}Ou(OO'v(SO'n$ti'u$ti}$ti!w$ti~O'[$ti#i$ti~P$'tOr'}Ou(OO'n$vi'u$vi'v$vi}$vi!w$vi~O'[$vi#i$vi~P$(gO#i1VO~P!#lO|1XO'W$_O}&nX!_&nX~O},yO!_'{a~O},yO!X!vO!_'{a~O},yO!X!vO'n&jO!_'{a~O'[$ci}$ci#i$ci!w$ci~P!#lO|1`O'W(^Oz&pX}&pX~P!$ZO}-QOz'|a~O}-QOz'|a~P!#lO!X!vO~O!X!vO#_1jO~Oi1nO!X!vO'n&jO~O}'_i'['_i~P!#lO!w1qO}'_i'['_i~P!#lO!_1tO~O^$Vq}$Vq'R$Vqz$Vq!_$Vq'c$Vq!P$Vq$|$Vq!X$Vq~P!)`O}1xO!P'}X~P!#lO!P&_O$|1{O~O!P&_O$|1{O~P!#lO!P$aX$qZX^$aX'R$aX~P!!cO$q2POrfXufX!PfX'nfX'ufX'vfX^fX'RfX~O$q2PO~O$}2WO'W)cO}&yX!O&yX~O}.SO!O(Ta~OY2[O~O[2]O~O]2`O~OR2bO!P&_O!k2aO$|1{O~O^$ZO'R$ZO~P!#lO!P#xO~P!#lO}2gO!w2iO!O(QX~O!O2jO~Ou(gO!S2sO!T2lO!U2lO!n2rO!o2qO!p2qO!t2pO'X$aO'd(cO'm+aO~O!O2oO~P$0uOR2zO!P.oO!k2yO$|2xO~OR2zO!P.oO!k2yO$|2xO']$bO~O'W(uO}&xX!O&xX~O}.{O!O(Ra~O'd3TO~O]3VO~O[3XO~O!_3[O~P){O^3^O~O^3^O~P){O#_3`O%n3aO~PEuO_/cO!O3eO%|/bO~P`O!X3gO~O&R3hOP&OqQ&OqW&Oq]&Oq^&Oqa&Oqb&Oqg&Oqi&Oqj&Oqk&Oqn&Oqp&Oqu&Oqw&Oqx&Oqy&Oq!P&Oq!Z&Oq!`&Oq!c&Oq!d&Oq!e&Oq!f&Oq!g&Oq!j&Oq#`&Oq#p&Oq#t&Oq${&Oq$}&Oq%P&Oq%Q&Oq%T&Oq%V&Oq%Y&Oq%Z&Oq%]&Oq%j&Oq%p&Oq%r&Oq%t&Oq%v&Oq%y&Oq&P&Oq&T&Oq&V&Oq&X&Oq&Z&Oq&]&Oq&|&Oq'W&Oq'a&Oq'm&Oq'z&Oq!O&Oq%w&Oq_&Oq%|&Oq~O}#Pi!O#Pi~P#(|O!w3jO}#Pi!O#Pi~O}!Ri!O!Ri~P#(|O^$ZO!w3qO'R$ZO~O^$ZO!X!vO!w3qO'R$ZO~O!T3uO!U3uO'X$aO'd(cO'm+aO~O^$ZO!X!vO!`$WO!f3vO!w3qO'R$ZO']$bO'n&jO~O!S3wO~P$9_O!S3wO!q3zO!t3{O~P$9_O^$ZO!X!vO!f3vO!w3qO'R$ZO'n&jO~O}'pq!_'pq^'pq'R'pq~P!)`O}&oO!_'oq~O#S$tiP$tiY$ti^$tii$tis$ti!]$ti!^$ti!`$ti!f$ti#W$ti#X$ti#Y$ti#Z$ti#[$ti#]$ti#^$ti#_$ti#a$ti#c$ti#e$ti#f$ti'R$ti'a$ti!_$tiz$ti!P$ti'c$ti$|$ti!X$ti~P$'tO#S$viP$viY$vi^$vii$vis$vi!]$vi!^$vi!`$vi!f$vi#W$vi#X$vi#Y$vi#Z$vi#[$vi#]$vi#^$vi#_$vi#a$vi#c$vi#e$vi#f$vi'R$vi'a$vi!_$viz$vi!P$vi'c$vi$|$vi!X$vi~P$(gO#S$ciP$ciY$ci^$cii$cis$ci}$ci!]$ci!^$ci!`$ci!f$ci#W$ci#X$ci#Y$ci#Z$ci#[$ci#]$ci#^$ci#_$ci#a$ci#c$ci#e$ci#f$ci'R$ci'a$ci!_$ciz$ci!P$ci!w$ci'c$ci$|$ci!X$ci~P!#lO}&ea'[&ea~P!#lO}&fa!_&fa~P!)`O},YO!_'li~O#i!zi}!zi!O!zi~P#(|OP#]Or!zOs!zOu!{O!^!xO!`!yO!f#]O'aQOY#Vii#Vi!]#Vi#X#Vi#Y#Vi#Z#Vi#[#Vi#]#Vi#^#Vi#_#Vi#a#Vi#c#Vi#e#Vi#f#Vi#i#Vi'n#Vi'u#Vi'v#Vi}#Vi!O#Vi~O#W#Vi~P$BuO#W9YO~P$BuOP#]Or!zOs!zOu!{O!^!xO!`!yO!f#]O#W9YO#X9ZO#Y9ZO#Z9ZO'aQOY#Vi!]#Vi#[#Vi#]#Vi#^#Vi#_#Vi#a#Vi#c#Vi#e#Vi#f#Vi#i#Vi'n#Vi'u#Vi'v#Vi}#Vi!O#Vi~Oi#Vi~P$D}Oi9[O~P$D}OP#]Oi9[Or!zOs!zOu!{O!^!xO!`!yO!f#]O#W9YO#X9ZO#Y9ZO#Z9ZO#[9]O'aQO#a#Vi#c#Vi#e#Vi#f#Vi#i#Vi'n#Vi'u#Vi'v#Vi}#Vi!O#Vi~OY#Vi!]#Vi#]#Vi#^#Vi#_#Vi~P$GVOY9gO!]9^O#]9^O#^9^O#_9^O~P$GVOP#]OY9gOi9[Or!zOs!zOu!{O!]9^O!^!xO!`!yO!f#]O#W9YO#X9ZO#Y9ZO#Z9ZO#[9]O#]9^O#^9^O#_9^O#a9_O'aQO#c#Vi#e#Vi#f#Vi#i#Vi'n#Vi'v#Vi}#Vi!O#Vi~O'u#Vi~P$IkO'u!|O~P$IkOP#]OY9gOi9[Or!zOs!zOu!{O!]9^O!^!xO!`!yO!f#]O#W9YO#X9ZO#Y9ZO#Z9ZO#[9]O#]9^O#^9^O#_9^O#a9_O#c9aO'aQO'u!|O#e#Vi#f#Vi#i#Vi'n#Vi}#Vi!O#Vi~O'v#Vi~P$KsO'v!}O~P$KsOP#]OY9gOi9[Or!zOs!zOu!{O!]9^O!^!xO!`!yO!f#]O#W9YO#X9ZO#Y9ZO#Z9ZO#[9]O#]9^O#^9^O#_9^O#a9_O#c9aO#e9cO'aQO'u!|O'v!}O~O#f#Vi#i#Vi'n#Vi}#Vi!O#Vi~P$M{O^#gy}#gy'R#gyz#gy!_#gy'c#gy!P#gy$|#gy!X#gy~P!)`OP#ViY#Vii#Vis#Vi!]#Vi!^#Vi!`#Vi!f#Vi#W#Vi#X#Vi#Y#Vi#Z#Vi#[#Vi#]#Vi#^#Vi#_#Vi#a#Vi#c#Vi#e#Vi#f#Vi#i#Vi'a#Vi}#Vi!O#Vi~P!#lO!^!xOP'`XY'`Xi'`Xr'`Xs'`Xu'`X!]'`X!`'`X!f'`X#W'`X#X'`X#Y'`X#Z'`X#['`X#]'`X#^'`X#_'`X#a'`X#c'`X#e'`X#f'`X#i'`X'a'`X'n'`X'u'`X'v'`X}'`X!O'`X~O#i#ji}#ji!O#ji~P#(|O!O4]O~O}&ma!O&ma~P#(|O!X!vO'n&jO}&na!_&na~O},yO!_'{i~O},yO!X!vO!_'{i~Oz&pa}&pa~P!#lO!X4dO~O}-QOz'|i~P!#lO}-QOz'|i~Oz4jO~O!X!vO#_4pO~Oi4qO!X!vO'n&jO~Oz4sO~O'[$eq}$eq#i$eq!w$eq~P!#lO^$Vy}$Vy'R$Vyz$Vy!_$Vy'c$Vy!P$Vy$|$Vy!X$Vy~P!)`O}1xO!P'}a~O!P&_O$|4xO~O!P&_O$|4xO~P!#lO^!zy}!zy'R!zyz!zy!_!zy'c!zy!P!zy$|!zy!X!zy~P!)`OY4{O~O}.SO!O(Ti~O]5QO~O[5RO~O'd'OO}&uX!O&uX~O}2gO!O(Qa~O!O5`O~P$0uOu-cO'd(cO'm+aO~O!S5cO!T5bO!U5bO!t0TO'X$aO'd(cO'm+aO~O!o5dO!p5dO~P%,eO!T5bO!U5bO'X$aO'd(cO'm+aO~O!P.oO~O!P.oO$|5fO~O!P.oO$|5fO~P!#lOR5kO!P.oO!k5jO$|5fO~OY5pO}&xa!O&xa~O}.{O!O(Ri~O]5sO~O!_5tO~O!_5uO~O!_5vO~O!_5vO~P){O^5xO~O!X5{O~O!_5}O~O}'si!O'si~P#(|O^$ZO'R$ZO~P!)`O^$ZO!w6SO'R$ZO~O^$ZO!X!vO!w6SO'R$ZO~O!T6XO!U6XO'X$aO'd(cO'm+aO~O^$ZO!X!vO!f6YO!w6SO'R$ZO'n&jO~O!`$WO']$bO~P%1PO!S6ZO~P%0nO}'py!_'py^'py'R'py~P!)`O#S$eqP$eqY$eq^$eqi$eqs$eq}$eq!]$eq!^$eq!`$eq!f$eq#W$eq#X$eq#Y$eq#Z$eq#[$eq#]$eq#^$eq#_$eq#a$eq#c$eq#e$eq#f$eq'R$eq'a$eq!_$eqz$eq!P$eq!w$eq'c$eq$|$eq!X$eq~P!#lO}&fi!_&fi~P!)`O#i!zq}!zq!O!zq~P#(|Or-iOs-iOu-jOPoaYoaioa!]oa!^oa!`oa!foa#Woa#Xoa#Yoa#Zoa#[oa#]oa#^oa#_oa#aoa#coa#eoa#foa#ioa'aoa'noa'uoa'voa}oa!Ooa~Or'}Ou(OOP$YaY$Yai$Yas$Ya!]$Ya!^$Ya!`$Ya!f$Ya#W$Ya#X$Ya#Y$Ya#Z$Ya#[$Ya#]$Ya#^$Ya#_$Ya#a$Ya#c$Ya#e$Ya#f$Ya#i$Ya'a$Ya'n$Ya'u$Ya'v$Ya}$Ya!O$Ya~Or'}Ou(OOP$[aY$[ai$[as$[a!]$[a!^$[a!`$[a!f$[a#W$[a#X$[a#Y$[a#Z$[a#[$[a#]$[a#^$[a#_$[a#a$[a#c$[a#e$[a#f$[a#i$[a'a$[a'n$[a'u$[a'v$[a}$[a!O$[a~OP$jaY$jai$jas$ja!]$ja!^$ja!`$ja!f$ja#W$ja#X$ja#Y$ja#Z$ja#[$ja#]$ja#^$ja#_$ja#a$ja#c$ja#e$ja#f$ja#i$ja'a$ja}$ja!O$ja~P!#lO#i$Uq}$Uq!O$Uq~P#(|O#i$Vq}$Vq!O$Vq~P#(|O!O6eO~O'[$xy}$xy#i$xy!w$xy~P!#lO!X!vO}&ni!_&ni~O!X!vO'n&jO}&ni!_&ni~O},yO!_'{q~Oz&pi}&pi~P!#lO}-QOz'|q~Oz6lO~P!#lOz6lO~O}'_y'['_y~P!#lO}&sa!P&sa~P!#lO!P$pq^$pq'R$pq~P!#lOY6tO~O}.SO!O(Tq~O]6wO~O!P&_O$|6xO~O!P&_O$|6xO~P!#lO!w6yO}&ua!O&ua~O}2gO!O(Qi~P#(|O!T7PO!U7PO'X$aO'd(cO'm+aO~O!S7RO!t3{O~P%@nO!P.oO$|7UO~O!P.oO$|7UO~P!#lO'd7[O~O}.{O!O(Rq~O!_7_O~O!_7_O~P){O!_7aO~O!_7bO~O}#Py!O#Py~P#(|O^$ZO!w7hO'R$ZO~O^$ZO!X!vO!w7hO'R$ZO~O!T7kO!U7kO'X$aO'd(cO'm+aO~O^$ZO!X!vO!f7lO!w7hO'R$ZO'n&jO~O#S$xyP$xyY$xy^$xyi$xys$xy}$xy!]$xy!^$xy!`$xy!f$xy#W$xy#X$xy#Y$xy#Z$xy#[$xy#]$xy#^$xy#_$xy#a$xy#c$xy#e$xy#f$xy'R$xy'a$xy!_$xyz$xy!P$xy!w$xy'c$xy$|$xy!X$xy~P!#lO#i#gy}#gy!O#gy~P#(|OP$ciY$cii$cis$ci!]$ci!^$ci!`$ci!f$ci#W$ci#X$ci#Y$ci#Z$ci#[$ci#]$ci#^$ci#_$ci#a$ci#c$ci#e$ci#f$ci#i$ci'a$ci}$ci!O$ci~P!#lOr'}Ou(OO'v(SOP$tiY$tii$tis$ti!]$ti!^$ti!`$ti!f$ti#W$ti#X$ti#Y$ti#Z$ti#[$ti#]$ti#^$ti#_$ti#a$ti#c$ti#e$ti#f$ti#i$ti'a$ti'n$ti'u$ti}$ti!O$ti~Or'}Ou(OOP$viY$vii$vis$vi!]$vi!^$vi!`$vi!f$vi#W$vi#X$vi#Y$vi#Z$vi#[$vi#]$vi#^$vi#_$vi#a$vi#c$vi#e$vi#f$vi#i$vi'a$vi'n$vi'u$vi'v$vi}$vi!O$vi~O#i$Vy}$Vy!O$Vy~P#(|O#i!zy}!zy!O!zy~P#(|O!X!vO}&nq!_&nq~O},yO!_'{y~Oz&pq}&pq~P!#lOz7rO~P!#lO}.SO!O(Ty~O}2gO!O(Qq~O!T8OO!U8OO'X$aO'd(cO'm+aO~O!P.oO$|8RO~O!P.oO$|8RO~P!#lO!_8UO~O&R8VOP&O!ZQ&O!ZW&O!Z]&O!Z^&O!Za&O!Zb&O!Zg&O!Zi&O!Zj&O!Zk&O!Zn&O!Zp&O!Zu&O!Zw&O!Zx&O!Zy&O!Z!P&O!Z!Z&O!Z!`&O!Z!c&O!Z!d&O!Z!e&O!Z!f&O!Z!g&O!Z!j&O!Z#`&O!Z#p&O!Z#t&O!Z${&O!Z$}&O!Z%P&O!Z%Q&O!Z%T&O!Z%V&O!Z%Y&O!Z%Z&O!Z%]&O!Z%j&O!Z%p&O!Z%r&O!Z%t&O!Z%v&O!Z%y&O!Z&P&O!Z&T&O!Z&V&O!Z&X&O!Z&Z&O!Z&]&O!Z&|&O!Z'W&O!Z'a&O!Z'm&O!Z'z&O!Z!O&O!Z%w&O!Z_&O!Z%|&O!Z~O^$ZO!w8[O'R$ZO~O^$ZO!X!vO!w8[O'R$ZO~OP$eqY$eqi$eqs$eq!]$eq!^$eq!`$eq!f$eq#W$eq#X$eq#Y$eq#Z$eq#[$eq#]$eq#^$eq#_$eq#a$eq#c$eq#e$eq#f$eq#i$eq'a$eq}$eq!O$eq~P!#lO}&uq!O&uq~P#(|O^$ZO!w8qO'R$ZO~OP$xyY$xyi$xys$xy!]$xy!^$xy!`$xy!f$xy#W$xy#X$xy#Y$xy#Z$xy#[$xy#]$xy#^$xy#_$xy#a$xy#c$xy#e$xy#f$xy#i$xy'a$xy}$xy!O$xy~P!#lO'c'eX~P.jO'cZXzZX!_ZX%nZX!PZX$|ZX!XZX~P$zO!XcX!_ZX!_cX'ncX~P;aOP9SOQ9SO]cOa:jOb!iOgcOi9SOjcOkcOn9SOp9SOuROwcOxcOycO!PSO!Z9UO!`UO!c9SO!d9SO!e9SO!f9SO!g9SO!j!hO#p!kO#t^O'W'^O'aQO'mYO'z:hO~O}9eO!O$Xa~O]#pOg#}Oi#qOj#pOk#pOn$OOp9jOu#wO!P#xO!Z:mO!`#uO#R9pO#p$SO$Z9lO$]9nO$`$TO'W&vO'a#rO~O#`'eO~P&+}O!OZX!OcX~P;aO#S9XO~O!X!vO#S9XO~O!w9hO~O#_9^O~O!w9qO}'sX!O'sX~O!w9hO}'qX!O'qX~O#S9rO~O'[9tO~P!#lO#S9yO~O#S9zO~O!X!vO#S9{O~O!X!vO#S9rO~O#i9|O~P#(|O#S9}O~O#S:OO~O#S:PO~O#S:QO~O#i:RO~P!#lO#i:SO~P!#lO#t~!^!n!p!q#Q#R'z$Z$]$`$q${$|$}%T%V%Y%Z%]%_~TS#t'z#Xy'T'U#v'T'W'd~", + goto: "#Dk(XPPPPPPP(YP(jP*^PPPP-sPP.Y3j5^5qP5qPPP5q5qP5qP7_PP7dP7xPPPPwPPP>}AYP`!>h!>l!>lP!;jP!>p!>pP!AcP!Agk|}?O}!O>k!O!P?`!P!QCl!Q!R!0[!R![!1q![!]!7s!]!^!8V!^!_!8g!_!`!9d!`!a!:[!a!b!U#R#S2`#S#T!>i#T#o2`#o#p!>y#p#q!?O#q#r!?f#r#s!?x#s$f%T$f$g%c$g#BY2`#BY#BZ!@Y#BZ$IS2`$IS$I_!@Y$I_$I|2`$I|$I}!Bq$I}$JO!Bq$JO$JT2`$JT$JU!@Y$JU$KV2`$KV$KW!@Y$KW&FU2`&FU&FV!@Y&FV?HT2`?HT?HU!@Y?HU~2`W%YR$QWO!^%T!_#o%T#p~%T,T%jg$QW'T+{OX%TXY%cYZ%TZ[%c[p%Tpq%cq!^%T!_#o%T#p$f%T$f$g%c$g#BY%T#BY#BZ%c#BZ$IS%T$IS$I_%c$I_$JT%T$JT$JU%c$JU$KV%T$KV$KW%c$KW&FU%T&FU&FV%c&FV?HT%T?HT?HU%c?HU~%T,T'YR$QW'U+{O!^%T!_#o%T#p~%T$T'jS$QW!f#{O!^%T!_!`'v!`#o%T#p~%T$O'}S#a#v$QWO!^%T!_!`(Z!`#o%T#p~%T$O(bR#a#v$QWO!^%T!_#o%T#p~%T'u(rZ$QW]!ROY(kYZ)eZr(krs*rs!^(k!^!_+U!_#O(k#O#P-b#P#o(k#o#p+U#p~(k&r)jV$QWOr)ers*Ps!^)e!^!_*a!_#o)e#o#p*a#p~)e&r*WR#{&j$QWO!^%T!_#o%T#p~%T&j*dROr*ars*ms~*a&j*rO#{&j'u*{R#{&j$QW]!RO!^%T!_#o%T#p~%T'm+ZV]!ROY+UYZ*aZr+Urs+ps#O+U#O#P+w#P~+U'm+wO#{&j]!R'm+zROr+Urs,Ts~+U'm,[U#{&j]!ROY,nZr,nrs-Vs#O,n#O#P-[#P~,n!R,sU]!ROY,nZr,nrs-Vs#O,n#O#P-[#P~,n!R-[O]!R!R-_PO~,n'u-gV$QWOr(krs-|s!^(k!^!_+U!_#o(k#o#p+U#p~(k'u.VZ#{&j$QW]!ROY.xYZ%TZr.xrs/rs!^.x!^!_,n!_#O.x#O#P0S#P#o.x#o#p,n#p~.x!Z/PZ$QW]!ROY.xYZ%TZr.xrs/rs!^.x!^!_,n!_#O.x#O#P0S#P#o.x#o#p,n#p~.x!Z/yR$QW]!RO!^%T!_#o%T#p~%T!Z0XT$QWO!^.x!^!_,n!_#o.x#o#p,n#p~.xy0mZ$QWOt%Ttu1`u!^%T!_!c%T!c!}1`!}#R%T#R#S1`#S#T%T#T#o1`#p$g%T$g~1`y1g]$QW'mqOt%Ttu1`u!Q%T!Q![1`![!^%T!_!c%T!c!}1`!}#R%T#R#S1`#S#T%T#T#o1`#p$g%T$g~1`&i2k_$QW#vS'W%k'dpOt%Ttu2`u}%T}!O3j!O!Q%T!Q![2`![!^%T!_!c%T!c!}2`!}#R%T#R#S2`#S#T%T#T#o2`#p$g%T$g~2`[3q_$QW#vSOt%Ttu3ju}%T}!O3j!O!Q%T!Q![3j![!^%T!_!c%T!c!}3j!}#R%T#R#S3j#S#T%T#T#o3j#p$g%T$g~3j$O4wS#Y#v$QWO!^%T!_!`5T!`#o%T#p~%T$O5[R$QW#k#vO!^%T!_#o%T#p~%T%r5lU'v%j$QWOv%Tvw6Ow!^%T!_!`5T!`#o%T#p~%T$O6VS$QW#e#vO!^%T!_!`5T!`#o%T#p~%T'u6jZ$QW]!ROY6cYZ7]Zw6cwx*rx!^6c!^!_8T!_#O6c#O#P:T#P#o6c#o#p8T#p~6c&r7bV$QWOw7]wx*Px!^7]!^!_7w!_#o7]#o#p7w#p~7]&j7zROw7wwx*mx~7w'm8YV]!ROY8TYZ7wZw8Twx+px#O8T#O#P8o#P~8T'm8rROw8Twx8{x~8T'm9SU#{&j]!ROY9fZw9fwx-Vx#O9f#O#P9}#P~9f!R9kU]!ROY9fZw9fwx-Vx#O9f#O#P9}#P~9f!R:QPO~9f'u:YV$QWOw6cwx:ox!^6c!^!_8T!_#o6c#o#p8T#p~6c'u:xZ#{&j$QW]!ROY;kYZ%TZw;kwx/rx!^;k!^!_9f!_#O;k#O#PW{!^%T!_!`5T!`#o%T#p~%T$O>_S#W#v$QWO!^%T!_!`5T!`#o%T#p~%T$u>rSi$m$QWO!^%T!_!`5T!`#o%T#p~%T&i?VR}&a$QWO!^%T!_#o%T#p~%T&i?gVr%n$QWO!O%T!O!P?|!P!Q%T!Q![@r![!^%T!_#o%T#p~%Ty@RT$QWO!O%T!O!P@b!P!^%T!_#o%T#p~%Ty@iR|q$QWO!^%T!_#o%T#p~%Ty@yZ$QWjqO!Q%T!Q![@r![!^%T!_!g%T!g!hAl!h#R%T#R#S@r#S#X%T#X#YAl#Y#o%T#p~%TyAqZ$QWO{%T{|Bd|}%T}!OBd!O!Q%T!Q![CO![!^%T!_#R%T#R#SCO#S#o%T#p~%TyBiV$QWO!Q%T!Q![CO![!^%T!_#R%T#R#SCO#S#o%T#p~%TyCVV$QWjqO!Q%T!Q![CO![!^%T!_#R%T#R#SCO#S#o%T#p~%T,TCs`$QW#X#vOYDuYZ%TZzDuz{Jl{!PDu!P!Q!-e!Q!^Du!^!_Fx!_!`!.^!`!a!/]!a!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~DuXD|[$QWyPOYDuYZ%TZ!PDu!P!QEr!Q!^Du!^!_Fx!_!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~DuXEy_$QWyPO!^%T!_#Z%T#Z#[Er#[#]%T#]#^Er#^#a%T#a#bEr#b#g%T#g#hEr#h#i%T#i#jEr#j#m%T#m#nEr#n#o%T#p~%TPF}VyPOYFxZ!PFx!P!QGd!Q!}Fx!}#OG{#O#PHh#P~FxPGiUyP#Z#[Gd#]#^Gd#a#bGd#g#hGd#i#jGd#m#nGdPHOTOYG{Z#OG{#O#PH_#P#QFx#Q~G{PHbQOYG{Z~G{PHkQOYFxZ~FxXHvY$QWOYHqYZ%TZ!^Hq!^!_G{!_#OHq#O#PIf#P#QDu#Q#oHq#o#pG{#p~HqXIkV$QWOYHqYZ%TZ!^Hq!^!_G{!_#oHq#o#pG{#p~HqXJVV$QWOYDuYZ%TZ!^Du!^!_Fx!_#oDu#o#pFx#p~Du,TJs^$QWyPOYJlYZKoZzJlz{NQ{!PJl!P!Q!,R!Q!^Jl!^!_!!]!_!}Jl!}#O!'|#O#P!+a#P#oJl#o#p!!]#p~Jl,TKtV$QWOzKoz{LZ{!^Ko!^!_M]!_#oKo#o#pM]#p~Ko,TL`X$QWOzKoz{LZ{!PKo!P!QL{!Q!^Ko!^!_M]!_#oKo#o#pM]#p~Ko,TMSR$QWT+{O!^%T!_#o%T#p~%T+{M`ROzM]z{Mi{~M]+{MlTOzM]z{Mi{!PM]!P!QM{!Q~M]+{NQOT+{,TNX^$QWyPOYJlYZKoZzJlz{NQ{!PJl!P!Q! T!Q!^Jl!^!_!!]!_!}Jl!}#O!'|#O#P!+a#P#oJl#o#p!!]#p~Jl,T! ^_$QWT+{yPO!^%T!_#Z%T#Z#[Er#[#]%T#]#^Er#^#a%T#a#bEr#b#g%T#g#hEr#h#i%T#i#jEr#j#m%T#m#nEr#n#o%T#p~%T+{!!bYyPOY!!]YZM]Zz!!]z{!#Q{!P!!]!P!Q!&x!Q!}!!]!}#O!$`#O#P!&f#P~!!]+{!#VYyPOY!!]YZM]Zz!!]z{!#Q{!P!!]!P!Q!#u!Q!}!!]!}#O!$`#O#P!&f#P~!!]+{!#|UT+{yP#Z#[Gd#]#^Gd#a#bGd#g#hGd#i#jGd#m#nGd+{!$cWOY!$`YZM]Zz!$`z{!${{#O!$`#O#P!&S#P#Q!!]#Q~!$`+{!%OYOY!$`YZM]Zz!$`z{!${{!P!$`!P!Q!%n!Q#O!$`#O#P!&S#P#Q!!]#Q~!$`+{!%sTT+{OYG{Z#OG{#O#PH_#P#QFx#Q~G{+{!&VTOY!$`YZM]Zz!$`z{!${{~!$`+{!&iTOY!!]YZM]Zz!!]z{!#Q{~!!]+{!&}_yPOzM]z{Mi{#ZM]#Z#[!&x#[#]M]#]#^!&x#^#aM]#a#b!&x#b#gM]#g#h!&x#h#iM]#i#j!&x#j#mM]#m#n!&x#n~M],T!(R[$QWOY!'|YZKoZz!'|z{!(w{!^!'|!^!_!$`!_#O!'|#O#P!*o#P#QJl#Q#o!'|#o#p!$`#p~!'|,T!(|^$QWOY!'|YZKoZz!'|z{!(w{!P!'|!P!Q!)x!Q!^!'|!^!_!$`!_#O!'|#O#P!*o#P#QJl#Q#o!'|#o#p!$`#p~!'|,T!*PY$QWT+{OYHqYZ%TZ!^Hq!^!_G{!_#OHq#O#PIf#P#QDu#Q#oHq#o#pG{#p~Hq,T!*tX$QWOY!'|YZKoZz!'|z{!(w{!^!'|!^!_!$`!_#o!'|#o#p!$`#p~!'|,T!+fX$QWOYJlYZKoZzJlz{NQ{!^Jl!^!_!!]!_#oJl#o#p!!]#p~Jl,T!,Yc$QWyPOzKoz{LZ{!^Ko!^!_M]!_#ZKo#Z#[!,R#[#]Ko#]#^!,R#^#aKo#a#b!,R#b#gKo#g#h!,R#h#iKo#i#j!,R#j#mKo#m#n!,R#n#oKo#o#pM]#p~Ko,T!-lV$QWS+{OY!-eYZ%TZ!^!-e!^!_!.R!_#o!-e#o#p!.R#p~!-e+{!.WQS+{OY!.RZ~!.R$P!.g[$QW#k#vyPOYDuYZ%TZ!PDu!P!QEr!Q!^Du!^!_Fx!_!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~Du]!/f[#sS$QWyPOYDuYZ%TZ!PDu!P!QEr!Q!^Du!^!_Fx!_!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~Duy!0cd$QWjqO!O%T!O!P@r!P!Q%T!Q![!1q![!^%T!_!g%T!g!hAl!h#R%T#R#S!1q#S#U%T#U#V!3X#V#X%T#X#YAl#Y#b%T#b#c!2w#c#d!4m#d#l%T#l#m!5{#m#o%T#p~%Ty!1x_$QWjqO!O%T!O!P@r!P!Q%T!Q![!1q![!^%T!_!g%T!g!hAl!h#R%T#R#S!1q#S#X%T#X#YAl#Y#b%T#b#c!2w#c#o%T#p~%Ty!3OR$QWjqO!^%T!_#o%T#p~%Ty!3^W$QWO!Q%T!Q!R!3v!R!S!3v!S!^%T!_#R%T#R#S!3v#S#o%T#p~%Ty!3}Y$QWjqO!Q%T!Q!R!3v!R!S!3v!S!^%T!_#R%T#R#S!3v#S#b%T#b#c!2w#c#o%T#p~%Ty!4rV$QWO!Q%T!Q!Y!5X!Y!^%T!_#R%T#R#S!5X#S#o%T#p~%Ty!5`X$QWjqO!Q%T!Q!Y!5X!Y!^%T!_#R%T#R#S!5X#S#b%T#b#c!2w#c#o%T#p~%Ty!6QZ$QWO!Q%T!Q![!6s![!^%T!_!c%T!c!i!6s!i#R%T#R#S!6s#S#T%T#T#Z!6s#Z#o%T#p~%Ty!6z]$QWjqO!Q%T!Q![!6s![!^%T!_!c%T!c!i!6s!i#R%T#R#S!6s#S#T%T#T#Z!6s#Z#b%T#b#c!2w#c#o%T#p~%T%w!7|R!XV$QW#i%hO!^%T!_#o%T#p~%T!P!8^R^w$QWO!^%T!_#o%T#p~%T+c!8rR']d!]%Y#t&s'zP!P!Q!8{!^!_!9Q!_!`!9_W!9QO$SW#v!9VP#[#v!_!`!9Y#v!9_O#k#v#v!9dO#]#v%w!9kT!w%o$QWO!^%T!_!`'v!`!a!9z!a#o%T#p~%T$P!:RR#S#w$QWO!^%T!_#o%T#p~%T%w!:gT'[!s#]#v#}S$QWO!^%T!_!`!:v!`!a!;W!a#o%T#p~%T$O!:}R#]#v$QWO!^%T!_#o%T#p~%T$O!;_T#[#v$QWO!^%T!_!`5T!`!a!;n!a#o%T#p~%T$O!;uS#[#v$QWO!^%T!_!`5T!`#o%T#p~%T%w!]S#c#v$QWO!^%T!_!`5T!`#o%T#p~%T$P!>pR$QW'a#wO!^%T!_#o%T#p~%T~!?OO!P~%r!?VT'u%j$QWO!^%T!_!`5T!`#o%T#p#q!=P#q~%T$u!?oR!O$k$QW'cQO!^%T!_#o%T#p~%TX!@PR!gP$QWO!^%T!_#o%T#p~%T,T!@gr$QW'T+{#vS'W%k'dpOX%TXY%cYZ%TZ[%c[p%Tpq%cqt%Ttu2`u}%T}!O3j!O!Q%T!Q![2`![!^%T!_!c%T!c!}2`!}#R%T#R#S2`#S#T%T#T#o2`#p$f%T$f$g%c$g#BY2`#BY#BZ!@Y#BZ$IS2`$IS$I_!@Y$I_$JT2`$JT$JU!@Y$JU$KV2`$KV$KW!@Y$KW&FU2`&FU&FV!@Y&FV?HT2`?HT?HU!@Y?HU~2`,T!CO_$QW'U+{#vS'W%k'dpOt%Ttu2`u}%T}!O3j!O!Q%T!Q![2`![!^%T!_!c%T!c!}2`!}#R%T#R#S2`#S#T%T#T#o2`#p$g%T$g~2`", + tokenizers: [noSemicolon, incdecToken, template, 0, 1, 2, 3, 4, 5, 6, 7, 8, insertSemicolon], + topRules: {"Script":[0,6]}, + dialects: {jsx: 11282, ts: 11284}, + dynamicPrecedences: {"145":1,"172":1}, + specialized: [{term: 284, get: (value, stack) => (tsExtends(value, stack) << 1)},{term: 284, get: value => spec_identifier[value] || -1},{term: 296, get: value => spec_word[value] || -1},{term: 59, get: value => spec_LessThan[value] || -1}], + tokenPrec: 11305 +}); + +exports.parser = parser; + +},{"@lezer/common":34,"@lezer/lr":36}],36:[function(require,module,exports){ +(function (process){(function (){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var common = require('@lezer/common'); + +/// A parse stack. These are used internally by the parser to track +/// parsing progress. They also provide some properties and methods +/// that external code such as a tokenizer can use to get information +/// about the parse state. +class Stack { + /// @internal + constructor( + /// The parse that this stack is part of @internal + p, + /// Holds state, input pos, buffer index triplets for all but the + /// top state @internal + stack, + /// The current parse state @internal + state, + // The position at which the next reduce should take place. This + // can be less than `this.pos` when skipped expressions have been + // added to the stack (which should be moved outside of the next + // reduction) + /// @internal + reducePos, + /// The input position up to which this stack has parsed. + pos, + /// The dynamic score of the stack, including dynamic precedence + /// and error-recovery penalties + /// @internal + score, + // The output buffer. Holds (type, start, end, size) quads + // representing nodes created by the parser, where `size` is + // amount of buffer array entries covered by this node. + /// @internal + buffer, + // The base offset of the buffer. When stacks are split, the split + // instance shared the buffer history with its parent up to + // `bufferBase`, which is the absolute offset (including the + // offset of previous splits) into the buffer at which this stack + // starts writing. + /// @internal + bufferBase, + /// @internal + curContext, + /// @internal + lookAhead = 0, + // A parent stack from which this was split off, if any. This is + // set up so that it always points to a stack that has some + // additional buffer content, never to a stack with an equal + // `bufferBase`. + /// @internal + parent) { + this.p = p; + this.stack = stack; + this.state = state; + this.reducePos = reducePos; + this.pos = pos; + this.score = score; + this.buffer = buffer; + this.bufferBase = bufferBase; + this.curContext = curContext; + this.lookAhead = lookAhead; + this.parent = parent; } -} -function lineStructure(from, to, state) { - let ranges = [], pos = from, total = 0; - rangeset.RangeSet.spans(state.facet(decorations), from, to, { - span() { }, - point(from, to) { - if (from > pos) { - ranges.push({ from: pos, to: from }); - total += from - pos; - } - pos = to; - } - }, 20); // We're only interested in collapsed ranges of a significant size - if (pos < to) { - ranges.push({ from: pos, to }); - total += to - pos; + /// @internal + toString() { + return `[${this.stack.filter((_, i) => i % 3 == 0).concat(this.state)}]@${this.pos}${this.score ? "!" + this.score : ""}`; } - return { total, ranges }; -} -function findPosition({ total, ranges }, ratio) { - if (ratio <= 0) - return ranges[0].from; - if (ratio >= 1) - return ranges[ranges.length - 1].to; - let dist = Math.floor(total * ratio); - for (let i = 0;; i++) { - let { from, to } = ranges[i], size = to - from; - if (dist <= size) - return from + dist; - dist -= size; + // Start an empty stack + /// @internal + static start(p, state, pos = 0) { + let cx = p.parser.context; + return new Stack(p, [], state, pos, pos, 0, [], 0, cx ? new StackContext(cx, cx.start) : null, 0, null); + } + /// The stack's current [context](#lr.ContextTracker) value, if + /// any. Its type will depend on the context tracker's type + /// parameter, or it will be `null` if there is no context + /// tracker. + get context() { return this.curContext ? this.curContext.context : null; } + // Push a state onto the stack, tracking its start position as well + // as the buffer base at that point. + /// @internal + pushState(state, start) { + this.stack.push(this.state, start, this.bufferBase + this.buffer.length); + this.state = state; } -} -function findFraction(structure, pos) { - let counted = 0; - for (let { from, to } of structure.ranges) { - if (pos <= to) { - counted += pos - from; - break; + // Apply a reduce action + /// @internal + reduce(action) { + let depth = action >> 19 /* ReduceDepthShift */, type = action & 65535 /* ValueMask */; + let { parser } = this.p; + let dPrec = parser.dynamicPrecedence(type); + if (dPrec) + this.score += dPrec; + if (depth == 0) { + // Zero-depth reductions are a special case—they add stuff to + // the stack without popping anything off. + if (type < parser.minRepeatTerm) + this.storeNode(type, this.reducePos, this.reducePos, 4, true); + this.pushState(parser.getGoto(this.state, type, true), this.reducePos); + this.reduceContext(type, this.reducePos); + return; } - counted += to - from; - } - return counted / structure.total; -} -function cutRange(ranges, from, to) { - for (let i = 0; i < ranges.length; i++) { - let r = ranges[i]; - if (r.from < to && r.to > from) { - let pieces = []; - if (r.from < from) - pieces.push({ from: r.from, to: from }); - if (r.to > to) - pieces.push({ from: to, to: r.to }); - ranges.splice(i, 1, ...pieces); - i += pieces.length - 1; + // Find the base index into `this.stack`, content after which will + // be dropped. Note that with `StayFlag` reductions we need to + // consume two extra frames (the dummy parent node for the skipped + // expression and the state that we'll be staying in, which should + // be moved to `this.state`). + let base = this.stack.length - ((depth - 1) * 3) - (action & 262144 /* StayFlag */ ? 6 : 0); + let start = this.stack[base - 2]; + let bufferBase = this.stack[base - 1], count = this.bufferBase + this.buffer.length - bufferBase; + // Store normal terms or `R -> R R` repeat reductions + if (type < parser.minRepeatTerm || (action & 131072 /* RepeatFlag */)) { + let pos = parser.stateFlag(this.state, 1 /* Skipped */) ? this.pos : this.reducePos; + this.storeNode(type, start, pos, count + 4, true); } - } -} -function find(array, f) { - for (let val of array) - if (f(val)) - return val; - return undefined; -} -// Don't scale when the document height is within the range of what -// the DOM can handle. -const IdScaler = { - toDOM(n) { return n; }, - fromDOM(n) { return n; }, - scale: 1 -}; -// When the height is too big (> VP.MaxDOMHeight), scale down the -// regions outside the viewports so that the total height is -// VP.MaxDOMHeight. -class BigScaler { - constructor(doc, heightMap, viewports) { - let vpHeight = 0, base = 0, domBase = 0; - this.viewports = viewports.map(({ from, to }) => { - let top = heightMap.lineAt(from, QueryType.ByPos, doc, 0, 0).top; - let bottom = heightMap.lineAt(to, QueryType.ByPos, doc, 0, 0).bottom; - vpHeight += bottom - top; - return { from, to, top, bottom, domTop: 0, domBottom: 0 }; - }); - this.scale = (7000000 /* MaxDOMHeight */ - vpHeight) / (heightMap.height - vpHeight); - for (let obj of this.viewports) { - obj.domTop = domBase + (obj.top - base) * this.scale; - domBase = obj.domBottom = obj.domTop + (obj.bottom - obj.top); - base = obj.bottom; + if (action & 262144 /* StayFlag */) { + this.state = this.stack[base]; } - } - toDOM(n) { - for (let i = 0, base = 0, domBase = 0;; i++) { - let vp = i < this.viewports.length ? this.viewports[i] : null; - if (!vp || n < vp.top) - return domBase + (n - base) * this.scale; - if (n <= vp.bottom) - return vp.domTop + (n - vp.top); - base = vp.bottom; - domBase = vp.domBottom; + else { + let baseStateID = this.stack[base - 3]; + this.state = parser.getGoto(baseStateID, type, true); } + while (this.stack.length > base) + this.stack.pop(); + this.reduceContext(type, start); } - fromDOM(n) { - for (let i = 0, base = 0, domBase = 0;; i++) { - let vp = i < this.viewports.length ? this.viewports[i] : null; - if (!vp || n < vp.domTop) - return base + (n - domBase) / this.scale; - if (n <= vp.domBottom) - return vp.top + (n - vp.domTop); - base = vp.bottom; - domBase = vp.domBottom; + // Shift a value into the buffer + /// @internal + storeNode(term, start, end, size = 4, isReduce = false) { + if (term == 0 /* Err */) { // Try to omit/merge adjacent error nodes + let cur = this, top = this.buffer.length; + if (top == 0 && cur.parent) { + top = cur.bufferBase - cur.parent.bufferBase; + cur = cur.parent; + } + if (top > 0 && cur.buffer[top - 4] == 0 /* Err */ && cur.buffer[top - 1] > -1) { + if (start == end) + return; + if (cur.buffer[top - 2] >= start) { + cur.buffer[top - 2] = end; + return; + } + } + } + if (!isReduce || this.pos == end) { // Simple case, just append + this.buffer.push(term, start, end, size); + } + else { // There may be skipped nodes that have to be moved forward + let index = this.buffer.length; + if (index > 0 && this.buffer[index - 4] != 0 /* Err */) + while (index > 0 && this.buffer[index - 2] > end) { + // Move this record forward + this.buffer[index] = this.buffer[index - 4]; + this.buffer[index + 1] = this.buffer[index - 3]; + this.buffer[index + 2] = this.buffer[index - 2]; + this.buffer[index + 3] = this.buffer[index - 1]; + index -= 4; + if (size > 4) + size -= 4; + } + this.buffer[index] = term; + this.buffer[index + 1] = start; + this.buffer[index + 2] = end; + this.buffer[index + 3] = size; } } -} -function scaleBlock(block, scaler) { - if (scaler.scale == 1) - return block; - let bTop = scaler.toDOM(block.top), bBottom = scaler.toDOM(block.bottom); - return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler)) : block.type); -} - -const theme = state.Facet.define({ combine: strs => strs.join(" ") }); -const darkTheme = state.Facet.define({ combine: values => values.indexOf(true) > -1 }); -const baseThemeID = styleMod.StyleModule.newName(), baseLightID = styleMod.StyleModule.newName(), baseDarkID = styleMod.StyleModule.newName(); -const lightDarkIDs = { "&light": "." + baseLightID, "&dark": "." + baseDarkID }; -function buildTheme(main, spec, scopes) { - return new styleMod.StyleModule(spec, { - finish(sel) { - return /&/.test(sel) ? sel.replace(/&\w*/, m => { - if (m == "&") - return main; - if (!scopes || !scopes[m]) - throw new RangeError(`Unsupported selector: ${m}`); - return scopes[m]; - }) : main + " " + sel; + // Apply a shift action + /// @internal + shift(action, next, nextEnd) { + let start = this.pos; + if (action & 131072 /* GotoFlag */) { + this.pushState(action & 65535 /* ValueMask */, this.pos); } - }); -} -const baseTheme = buildTheme("." + baseThemeID, { - "&.cm-editor": { - position: "relative !important", - boxSizing: "border-box", - "&.cm-focused": { - // Provide a simple default outline to make sure a focused - // editor is visually distinct. Can't leave the default behavior - // because that will apply to the content element, which is - // inside the scrollable container and doesn't include the - // gutters. We also can't use an 'auto' outline, since those - // are, for some reason, drawn behind the element content, which - // will cause things like the active line background to cover - // the outline (#297). - outline: "1px dotted #212121" - }, - display: "flex !important", - flexDirection: "column" - }, - ".cm-scroller": { - display: "flex !important", - alignItems: "flex-start !important", - fontFamily: "monospace", - lineHeight: 1.4, - height: "100%", - overflowX: "auto", - position: "relative", - zIndex: 0 - }, - ".cm-content": { - margin: 0, - flexGrow: 2, - minHeight: "100%", - display: "block", - whiteSpace: "pre", - wordWrap: "normal", - boxSizing: "border-box", - padding: "4px 0", - outline: "none", - "&[contenteditable=true]": { - WebkitUserModify: "read-write-plaintext-only", + else if ((action & 262144 /* StayFlag */) == 0) { // Regular shift + let nextState = action, { parser } = this.p; + if (nextEnd > this.pos || next <= parser.maxNode) { + this.pos = nextEnd; + if (!parser.stateFlag(nextState, 1 /* Skipped */)) + this.reducePos = nextEnd; + } + this.pushState(nextState, start); + this.shiftContext(next, start); + if (next <= parser.maxNode) + this.buffer.push(next, start, nextEnd, 4); } - }, - ".cm-lineWrapping": { - whiteSpace_fallback: "pre-wrap", - whiteSpace: "break-spaces", - wordBreak: "break-word", - overflowWrap: "anywhere" - }, - "&light .cm-content": { caretColor: "black" }, - "&dark .cm-content": { caretColor: "white" }, - ".cm-line": { - display: "block", - padding: "0 2px 0 4px" - }, - ".cm-selectionLayer": { - zIndex: -1, - contain: "size style" - }, - ".cm-selectionBackground": { - position: "absolute", - }, - "&light .cm-selectionBackground": { - background: "#d9d9d9" - }, - "&dark .cm-selectionBackground": { - background: "#222" - }, - "&light.cm-focused .cm-selectionBackground": { - background: "#d7d4f0" - }, - "&dark.cm-focused .cm-selectionBackground": { - background: "#233" - }, - ".cm-cursorLayer": { - zIndex: 100, - contain: "size style", - pointerEvents: "none" - }, - "&.cm-focused .cm-cursorLayer": { - animation: "steps(1) cm-blink 1.2s infinite" - }, - // Two animations defined so that we can switch between them to - // restart the animation without forcing another style - // recomputation. - "@keyframes cm-blink": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} }, - "@keyframes cm-blink2": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} }, - ".cm-cursor, .cm-dropCursor": { - position: "absolute", - borderLeft: "1.2px solid black", - marginLeft: "-0.6px", - pointerEvents: "none", - }, - ".cm-cursor": { - display: "none" - }, - "&dark .cm-cursor": { - borderLeftColor: "#444" - }, - "&.cm-focused .cm-cursor": { - display: "block" - }, - "&light .cm-activeLine": { backgroundColor: "#f3f9ff" }, - "&dark .cm-activeLine": { backgroundColor: "#223039" }, - "&light .cm-specialChar": { color: "red" }, - "&dark .cm-specialChar": { color: "#f78" }, - ".cm-tab": { - display: "inline-block", - overflow: "hidden", - verticalAlign: "bottom" - }, - ".cm-placeholder": { - color: "#888", - display: "inline-block", - verticalAlign: "top", - }, - ".cm-button": { - verticalAlign: "middle", - color: "inherit", - fontSize: "70%", - padding: ".2em 1em", - borderRadius: "1px" - }, - "&light .cm-button": { - backgroundImage: "linear-gradient(#eff1f5, #d9d9df)", - border: "1px solid #888", - "&:active": { - backgroundImage: "linear-gradient(#b4b4b4, #d0d3d6)" + else { // Shift-and-stay, which means this is a skipped token + this.pos = nextEnd; + this.shiftContext(next, start); + if (next <= this.p.parser.maxNode) + this.buffer.push(next, start, nextEnd, 4); } - }, - "&dark .cm-button": { - backgroundImage: "linear-gradient(#393939, #111)", - border: "1px solid #888", - "&:active": { - backgroundImage: "linear-gradient(#111, #333)" + } + // Apply an action + /// @internal + apply(action, next, nextEnd) { + if (action & 65536 /* ReduceFlag */) + this.reduce(action); + else + this.shift(action, next, nextEnd); + } + // Add a prebuilt (reused) node into the buffer. + /// @internal + useNode(value, next) { + let index = this.p.reused.length - 1; + if (index < 0 || this.p.reused[index] != value) { + this.p.reused.push(value); + index++; } - }, - ".cm-textfield": { - verticalAlign: "middle", - color: "inherit", - fontSize: "70%", - border: "1px solid silver", - padding: ".2em .5em" - }, - "&light .cm-textfield": { - backgroundColor: "white" - }, - "&dark .cm-textfield": { - border: "1px solid #555", - backgroundColor: "inherit" + let start = this.pos; + this.reducePos = this.pos = start + value.length; + this.pushState(next, start); + this.buffer.push(index, start, this.reducePos, -1 /* size == -1 means this is a reused value */); + if (this.curContext) + this.updateContext(this.curContext.tracker.reuse(this.curContext.context, value, this, this.p.stream.reset(this.pos - value.length))); } -}, lightDarkIDs); - -const observeOptions = { - childList: true, - characterData: true, - subtree: true, - attributes: true, - characterDataOldValue: true -}; -// IE11 has very broken mutation observers, so we also listen to -// DOMCharacterDataModified there -const useCharData = browser.ie && browser.ie_version <= 11; -class DOMObserver { - constructor(view, onChange, onScrollChanged) { - this.view = view; - this.onChange = onChange; - this.onScrollChanged = onScrollChanged; - this.active = false; - // The known selection. Kept in our own object, as opposed to just - // directly accessing the selection because: - // - Safari doesn't report the right selection in shadow DOM - // - Reading from the selection forces a DOM layout - // - This way, we can ignore selectionchange events if we have - // already seen the 'new' selection - this.selectionRange = new DOMSelectionState; - // Set when a selection change is detected, cleared on flush - this.selectionChanged = false; - this.delayedFlush = -1; - this.resizeTimeout = -1; - this.queue = []; - this.delayedAndroidKey = null; - this.scrollTargets = []; - this.intersection = null; - this.resize = null; - this.intersecting = false; - this.gapIntersection = null; - this.gaps = []; - // Timeout for scheduling check of the parents that need scroll handlers - this.parentCheck = -1; - this.dom = view.contentDOM; - this.observer = new MutationObserver(mutations => { - for (let mut of mutations) - this.queue.push(mut); - // IE11 will sometimes (on typing over a selection or - // backspacing out a single character text node) call the - // observer callback before actually updating the DOM. - // - // Unrelatedly, iOS Safari will, when ending a composition, - // sometimes first clear it, deliver the mutations, and then - // reinsert the finished text. CodeMirror's handling of the - // deletion will prevent the reinsertion from happening, - // breaking composition. - if ((browser.ie && browser.ie_version <= 11 || browser.ios && view.composing) && - mutations.some(m => m.type == "childList" && m.removedNodes.length || - m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length)) - this.flushSoon(); - else - this.flush(); - }); - if (useCharData) - this.onCharData = (event) => { - this.queue.push({ target: event.target, - type: "characterData", - oldValue: event.prevValue }); - this.flushSoon(); - }; - this.onSelectionChange = this.onSelectionChange.bind(this); - if (typeof ResizeObserver == "function") { - this.resize = new ResizeObserver(() => { - if (this.view.docView.lastUpdate < Date.now() - 75 && this.resizeTimeout < 0) - this.resizeTimeout = setTimeout(() => { - this.resizeTimeout = -1; - this.view.requestMeasure(); - }, 50); - }); - this.resize.observe(view.scrollDOM); + // Split the stack. Due to the buffer sharing and the fact + // that `this.stack` tends to stay quite shallow, this isn't very + // expensive. + /// @internal + split() { + let parent = this; + let off = parent.buffer.length; + // Because the top of the buffer (after this.pos) may be mutated + // to reorder reductions and skipped tokens, and shared buffers + // should be immutable, this copies any outstanding skipped tokens + // to the new buffer, and puts the base pointer before them. + while (off > 0 && parent.buffer[off - 2] > parent.reducePos) + off -= 4; + let buffer = parent.buffer.slice(off), base = parent.bufferBase + off; + // Make sure parent points to an actual parent with content, if there is such a parent. + while (parent && base == parent.bufferBase) + parent = parent.parent; + return new Stack(this.p, this.stack.slice(), this.state, this.reducePos, this.pos, this.score, buffer, base, this.curContext, this.lookAhead, parent); + } + // Try to recover from an error by 'deleting' (ignoring) one token. + /// @internal + recoverByDelete(next, nextEnd) { + let isNode = next <= this.p.parser.maxNode; + if (isNode) + this.storeNode(next, this.pos, nextEnd, 4); + this.storeNode(0 /* Err */, this.pos, nextEnd, isNode ? 8 : 4); + this.pos = this.reducePos = nextEnd; + this.score -= 190 /* Delete */; + } + /// Check if the given term would be able to be shifted (optionally + /// after some reductions) on this stack. This can be useful for + /// external tokenizers that want to make sure they only provide a + /// given token when it applies. + canShift(term) { + for (let sim = new SimulatedStack(this);;) { + let action = this.p.parser.stateSlot(sim.state, 4 /* DefaultReduce */) || this.p.parser.hasAction(sim.state, term); + if ((action & 65536 /* ReduceFlag */) == 0) + return true; + if (action == 0) + return false; + sim.reduce(action); } - this.start(); - this.onScroll = this.onScroll.bind(this); - window.addEventListener("scroll", this.onScroll); - if (typeof IntersectionObserver == "function") { - this.intersection = new IntersectionObserver(entries => { - if (this.parentCheck < 0) - this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000); - if (entries.length > 0 && (entries[entries.length - 1].intersectionRatio > 0) != this.intersecting) { - this.intersecting = !this.intersecting; - if (this.intersecting != this.view.inView) - this.onScrollChanged(document.createEvent("Event")); - } - }, {}); - this.intersection.observe(this.dom); - this.gapIntersection = new IntersectionObserver(entries => { - if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0) - this.onScrollChanged(document.createEvent("Event")); - }, {}); + } + // Apply up to Recover.MaxNext recovery actions that conceptually + // inserts some missing token or rule. + /// @internal + recoverByInsert(next) { + if (this.stack.length >= 300 /* MaxInsertStackDepth */) + return []; + let nextStates = this.p.parser.nextStates(this.state); + if (nextStates.length > 4 /* MaxNext */ << 1 || this.stack.length >= 120 /* DampenInsertStackDepth */) { + let best = []; + for (let i = 0, s; i < nextStates.length; i += 2) { + if ((s = nextStates[i + 1]) != this.state && this.p.parser.hasAction(s, next)) + best.push(nextStates[i], s); + } + if (this.stack.length < 120 /* DampenInsertStackDepth */) + for (let i = 0; best.length < 4 /* MaxNext */ << 1 && i < nextStates.length; i += 2) { + let s = nextStates[i + 1]; + if (!best.some((v, i) => (i & 1) && v == s)) + best.push(nextStates[i], s); + } + nextStates = best; } - this.listenForScroll(); - this.readSelectionRange(); - this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange); + let result = []; + for (let i = 0; i < nextStates.length && result.length < 4 /* MaxNext */; i += 2) { + let s = nextStates[i + 1]; + if (s == this.state) + continue; + let stack = this.split(); + stack.storeNode(0 /* Err */, stack.pos, stack.pos, 4, true); + stack.pushState(s, this.pos); + stack.shiftContext(nextStates[i], this.pos); + stack.score -= 200 /* Insert */; + result.push(stack); + } + return result; } - onScroll(e) { - if (this.intersecting) - this.flush(false); - this.onScrollChanged(e); + // Force a reduce, if possible. Return false if that can't + // be done. + /// @internal + forceReduce() { + let reduce = this.p.parser.stateSlot(this.state, 5 /* ForcedReduce */); + if ((reduce & 65536 /* ReduceFlag */) == 0) + return false; + let { parser } = this.p; + if (!parser.validAction(this.state, reduce)) { + let depth = reduce >> 19 /* ReduceDepthShift */, term = reduce & 65535 /* ValueMask */; + let target = this.stack.length - depth * 3; + if (target < 0 || parser.getGoto(this.stack[target], term, false) < 0) + return false; + this.storeNode(0 /* Err */, this.reducePos, this.reducePos, 4, true); + this.score -= 100 /* Reduce */; + } + this.reduce(reduce); + return true; } - updateGaps(gaps) { - if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) { - this.gapIntersection.disconnect(); - for (let gap of gaps) - this.gapIntersection.observe(gap); - this.gaps = gaps; + /// @internal + forceAll() { + while (!this.p.parser.stateFlag(this.state, 2 /* Accepting */)) { + if (!this.forceReduce()) { + this.storeNode(0 /* Err */, this.pos, this.pos, 4, true); + break; + } } + return this; } - onSelectionChange(event) { - if (!this.readSelectionRange() || this.delayedAndroidKey) - return; - let { view } = this, sel = this.selectionRange; - if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(view.dom, sel)) - return; - let context = sel.anchorNode && view.docView.nearest(sel.anchorNode); - if (context && context.ignoreEvent(event)) - return; - // Deletions on IE11 fire their events in the wrong order, giving - // us a selection change event before the DOM changes are - // reported. - // Chrome Android has a similar issue when backspacing out a - // selection (#645). - if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty && - // (Selection.isCollapsed isn't reliable on IE) - sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset)) - this.flushSoon(); - else - this.flush(false); + /// Check whether this state has no further actions (assumed to be a direct descendant of the + /// top state, since any other states must be able to continue + /// somehow). @internal + get deadEnd() { + if (this.stack.length != 3) + return false; + let { parser } = this.p; + return parser.data[parser.stateSlot(this.state, 1 /* Actions */)] == 65535 /* End */ && + !parser.stateSlot(this.state, 4 /* DefaultReduce */); } - readSelectionRange() { - let { root } = this.view, domSel = getSelection(root); - // The Selection object is broken in shadow roots in Safari. See - // https://github.com/codemirror/codemirror.next/issues/414 - let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.view.contentDOM && - safariSelectionRangeHack(this.view) || domSel; - if (this.selectionRange.eq(range)) + /// Restart the stack (put it back in its start state). Only safe + /// when this.stack.length == 3 (state is directly below the top + /// state). @internal + restart() { + this.state = this.stack[0]; + this.stack.length = 0; + } + /// @internal + sameState(other) { + if (this.state != other.state || this.stack.length != other.stack.length) return false; - this.selectionRange.setRange(range); - return this.selectionChanged = true; + for (let i = 0; i < this.stack.length; i += 3) + if (this.stack[i] != other.stack[i]) + return false; + return true; } - setSelectionRange(anchor, head) { - this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset); - this.selectionChanged = false; + /// Get the parser used by this stack. + get parser() { return this.p.parser; } + /// Test whether a given dialect (by numeric ID, as exported from + /// the terms file) is enabled. + dialectEnabled(dialectID) { return this.p.parser.dialect.flags[dialectID]; } + shiftContext(term, start) { + if (this.curContext) + this.updateContext(this.curContext.tracker.shift(this.curContext.context, term, this, this.p.stream.reset(start))); } - listenForScroll() { - this.parentCheck = -1; - let i = 0, changed = null; - for (let dom = this.dom; dom;) { - if (dom.nodeType == 1) { - if (!changed && i < this.scrollTargets.length && this.scrollTargets[i] == dom) - i++; - else if (!changed) - changed = this.scrollTargets.slice(0, i); - if (changed) - changed.push(dom); - dom = dom.assignedSlot || dom.parentNode; - } - else if (dom.nodeType == 11) { // Shadow root - dom = dom.host; - } - else { - break; - } + reduceContext(term, start) { + if (this.curContext) + this.updateContext(this.curContext.tracker.reduce(this.curContext.context, term, this, this.p.stream.reset(start))); + } + /// @internal + emitContext() { + let last = this.buffer.length - 1; + if (last < 0 || this.buffer[last] != -3) + this.buffer.push(this.curContext.hash, this.reducePos, this.reducePos, -3); + } + /// @internal + emitLookAhead() { + let last = this.buffer.length - 1; + if (last < 0 || this.buffer[last] != -4) + this.buffer.push(this.lookAhead, this.reducePos, this.reducePos, -4); + } + updateContext(context) { + if (context != this.curContext.context) { + let newCx = new StackContext(this.curContext.tracker, context); + if (newCx.hash != this.curContext.hash) + this.emitContext(); + this.curContext = newCx; } - if (i < this.scrollTargets.length && !changed) - changed = this.scrollTargets.slice(0, i); - if (changed) { - for (let dom of this.scrollTargets) - dom.removeEventListener("scroll", this.onScroll); - for (let dom of this.scrollTargets = changed) - dom.addEventListener("scroll", this.onScroll); + } + /// @internal + setLookAhead(lookAhead) { + if (lookAhead > this.lookAhead) { + this.emitLookAhead(); + this.lookAhead = lookAhead; } } - ignore(f) { - if (!this.active) - return f(); - try { - this.stop(); - return f(); + /// @internal + close() { + if (this.curContext && this.curContext.tracker.strict) + this.emitContext(); + if (this.lookAhead > 0) + this.emitLookAhead(); + } +} +class StackContext { + constructor(tracker, context) { + this.tracker = tracker; + this.context = context; + this.hash = tracker.strict ? tracker.hash(context) : 0; + } +} +var Recover; +(function (Recover) { + Recover[Recover["Insert"] = 200] = "Insert"; + Recover[Recover["Delete"] = 190] = "Delete"; + Recover[Recover["Reduce"] = 100] = "Reduce"; + Recover[Recover["MaxNext"] = 4] = "MaxNext"; + Recover[Recover["MaxInsertStackDepth"] = 300] = "MaxInsertStackDepth"; + Recover[Recover["DampenInsertStackDepth"] = 120] = "DampenInsertStackDepth"; +})(Recover || (Recover = {})); +// Used to cheaply run some reductions to scan ahead without mutating +// an entire stack +class SimulatedStack { + constructor(start) { + this.start = start; + this.state = start.state; + this.stack = start.stack; + this.base = this.stack.length; + } + reduce(action) { + let term = action & 65535 /* ValueMask */, depth = action >> 19 /* ReduceDepthShift */; + if (depth == 0) { + if (this.stack == this.start.stack) + this.stack = this.stack.slice(); + this.stack.push(this.state, 0, 0); + this.base += 3; } - finally { - this.start(); - this.clear(); + else { + this.base -= (depth - 1) * 3; } + let goto = this.start.p.parser.getGoto(this.stack[this.base - 3], term, true); + this.state = goto; } - start() { - if (this.active) - return; - this.observer.observe(this.dom, observeOptions); - if (useCharData) - this.dom.addEventListener("DOMCharacterDataModified", this.onCharData); - this.active = true; +} +// This is given to `Tree.build` to build a buffer, and encapsulates +// the parent-stack-walking necessary to read the nodes. +class StackBufferCursor { + constructor(stack, pos, index) { + this.stack = stack; + this.pos = pos; + this.index = index; + this.buffer = stack.buffer; + if (this.index == 0) + this.maybeNext(); } - stop() { - if (!this.active) - return; - this.active = false; - this.observer.disconnect(); - if (useCharData) - this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData); + static create(stack, pos = stack.bufferBase + stack.buffer.length) { + return new StackBufferCursor(stack, pos, pos - stack.bufferBase); } - // Throw away any pending changes - clear() { - this.observer.takeRecords(); - this.queue.length = 0; - this.selectionChanged = false; + maybeNext() { + let next = this.stack.parent; + if (next != null) { + this.index = this.stack.bufferBase - next.bufferBase; + this.stack = next; + this.buffer = next.buffer; + } } - // Chrome Android, especially in combination with GBoard, not only - // doesn't reliably fire regular key events, but also often - // surrounds the effect of enter or backspace with a bunch of - // composition events that, when interrupted, cause text duplication - // or other kinds of corruption. This hack makes the editor back off - // from handling DOM changes for a moment when such a key is - // detected (via beforeinput or keydown), and then dispatches the - // key event, throwing away the DOM changes if it gets handled. - delayAndroidKey(key, keyCode) { - if (!this.delayedAndroidKey) - requestAnimationFrame(() => { - let key = this.delayedAndroidKey; - this.delayedAndroidKey = null; - let startState = this.view.state; - if (dispatchKey(this.view.contentDOM, key.key, key.keyCode)) - this.processRecords(); - else - this.flush(); - if (this.view.state == startState) - this.view.update([]); - }); - // Since backspace beforeinput is sometimes signalled spuriously, - // Enter always takes precedence. - if (!this.delayedAndroidKey || key == "Enter") - this.delayedAndroidKey = { key, keyCode }; + get id() { return this.buffer[this.index - 4]; } + get start() { return this.buffer[this.index - 3]; } + get end() { return this.buffer[this.index - 2]; } + get size() { return this.buffer[this.index - 1]; } + next() { + this.index -= 4; + this.pos -= 4; + if (this.index == 0) + this.maybeNext(); } - flushSoon() { - if (this.delayedFlush < 0) - this.delayedFlush = window.setTimeout(() => { this.delayedFlush = -1; this.flush(); }, 20); + fork() { + return new StackBufferCursor(this.stack, this.pos, this.index); } - forceFlush() { - if (this.delayedFlush >= 0) { - window.clearTimeout(this.delayedFlush); - this.delayedFlush = -1; - this.flush(); +} + +class CachedToken { + constructor() { + this.start = -1; + this.value = -1; + this.end = -1; + this.extended = -1; + this.lookAhead = 0; + this.mask = 0; + this.context = 0; + } +} +const nullToken = new CachedToken; +/// [Tokenizers](#lr.ExternalTokenizer) interact with the input +/// through this interface. It presents the input as a stream of +/// characters, tracking lookahead and hiding the complexity of +/// [ranges](#common.Parser.parse^ranges) from tokenizer code. +class InputStream { + /// @internal + constructor( + /// @internal + input, + /// @internal + ranges) { + this.input = input; + this.ranges = ranges; + /// @internal + this.chunk = ""; + /// @internal + this.chunkOff = 0; + /// Backup chunk + this.chunk2 = ""; + this.chunk2Pos = 0; + /// The character code of the next code unit in the input, or -1 + /// when the stream is at the end of the input. + this.next = -1; + /// @internal + this.token = nullToken; + this.rangeIndex = 0; + this.pos = this.chunkPos = ranges[0].from; + this.range = ranges[0]; + this.end = ranges[ranges.length - 1].to; + this.readNext(); + } + resolveOffset(offset, assoc) { + let range = this.range, index = this.rangeIndex; + let pos = this.pos + offset; + while (pos < range.from) { + if (!index) + return null; + let next = this.ranges[--index]; + pos -= range.from - next.to; + range = next; + } + while (assoc < 0 ? pos > range.to : pos >= range.to) { + if (index == this.ranges.length - 1) + return null; + let next = this.ranges[++index]; + pos += next.from - range.to; + range = next; } + return pos; } - processRecords() { - let records = this.queue; - for (let mut of this.observer.takeRecords()) - records.push(mut); - if (records.length) - this.queue = []; - let from = -1, to = -1, typeOver = false; - for (let record of records) { - let range = this.readMutation(record); - if (!range) - continue; - if (range.typeOver) - typeOver = true; - if (from == -1) { - ({ from, to } = range); + /// Look at a code unit near the stream position. `.peek(0)` equals + /// `.next`, `.peek(-1)` gives you the previous character, and so + /// on. + /// + /// Note that looking around during tokenizing creates dependencies + /// on potentially far-away content, which may reduce the + /// effectiveness incremental parsing—when looking forward—or even + /// cause invalid reparses when looking backward more than 25 code + /// units, since the library does not track lookbehind. + peek(offset) { + let idx = this.chunkOff + offset, pos, result; + if (idx >= 0 && idx < this.chunk.length) { + pos = this.pos + offset; + result = this.chunk.charCodeAt(idx); + } + else { + let resolved = this.resolveOffset(offset, 1); + if (resolved == null) + return -1; + pos = resolved; + if (pos >= this.chunk2Pos && pos < this.chunk2Pos + this.chunk2.length) { + result = this.chunk2.charCodeAt(pos - this.chunk2Pos); } else { - from = Math.min(range.from, from); - to = Math.max(range.to, to); + let i = this.rangeIndex, range = this.range; + while (range.to <= pos) + range = this.ranges[++i]; + this.chunk2 = this.input.chunk(this.chunk2Pos = pos); + if (pos + this.chunk2.length > range.to) + this.chunk2 = this.chunk2.slice(0, range.to - pos); + result = this.chunk2.charCodeAt(0); } } - return { from, to, typeOver }; + if (pos >= this.token.lookAhead) + this.token.lookAhead = pos + 1; + return result; } - // Apply pending changes, if any - flush(readSelection = true) { - // Completely hold off flushing when pending keys are set—the code - // managing those will make sure processRecords is called and the - // view is resynchronized after - if (this.delayedFlush >= 0 || this.delayedAndroidKey) - return; - if (readSelection) - this.readSelectionRange(); - let { from, to, typeOver } = this.processRecords(); - let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange); - if (from < 0 && !newSel) - return; - this.selectionChanged = false; - let startState = this.view.state; - this.onChange(from, to, typeOver); - // The view wasn't updated - if (this.view.state == startState) - this.view.update([]); + /// Accept a token. By default, the end of the token is set to the + /// current stream position, but you can pass an offset (relative to + /// the stream position) to change that. + acceptToken(token, endOffset = 0) { + let end = endOffset ? this.resolveOffset(endOffset, -1) : this.pos; + if (end == null || end < this.token.start) + throw new RangeError("Token end out of bounds"); + this.token.value = token; + this.token.end = end; } - readMutation(rec) { - let cView = this.view.docView.nearest(rec.target); - if (!cView || cView.ignoreMutation(rec)) - return null; - cView.markDirty(rec.type == "attributes"); - if (rec.type == "attributes") - cView.dirty |= 4 /* Attrs */; - if (rec.type == "childList") { - let childBefore = findChild(cView, rec.previousSibling || rec.target.previousSibling, -1); - let childAfter = findChild(cView, rec.nextSibling || rec.target.nextSibling, 1); - return { from: childBefore ? cView.posAfter(childBefore) : cView.posAtStart, - to: childAfter ? cView.posBefore(childAfter) : cView.posAtEnd, typeOver: false }; - } - else if (rec.type == "characterData") { - return { from: cView.posAtStart, to: cView.posAtEnd, typeOver: rec.target.nodeValue == rec.oldValue }; + getChunk() { + if (this.pos >= this.chunk2Pos && this.pos < this.chunk2Pos + this.chunk2.length) { + let { chunk, chunkPos } = this; + this.chunk = this.chunk2; + this.chunkPos = this.chunk2Pos; + this.chunk2 = chunk; + this.chunk2Pos = chunkPos; + this.chunkOff = this.pos - this.chunkPos; } else { - return null; - } - } - destroy() { - var _a, _b, _c; - this.stop(); - (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect(); - (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect(); - (_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect(); - for (let dom of this.scrollTargets) - dom.removeEventListener("scroll", this.onScroll); - window.removeEventListener("scroll", this.onScroll); - this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange); - clearTimeout(this.parentCheck); - clearTimeout(this.resizeTimeout); - } -} -function findChild(cView, dom, dir) { - while (dom) { - let curView = ContentView.get(dom); - if (curView && curView.parent == cView) - return curView; - let parent = dom.parentNode; - dom = parent != cView.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling; - } - return null; -} -// Used to work around a Safari Selection/shadow DOM bug (#414) -function safariSelectionRangeHack(view) { - let found = null; - // Because Safari (at least in 2018-2021) doesn't provide regular - // access to the selection inside a shadowroot, we have to perform a - // ridiculous hack to get at it—using `execCommand` to trigger a - // `beforeInput` event so that we can read the target range from the - // event. - function read(event) { - event.preventDefault(); - event.stopImmediatePropagation(); - found = event.getTargetRanges()[0]; + this.chunk2 = this.chunk; + this.chunk2Pos = this.chunkPos; + let nextChunk = this.input.chunk(this.pos); + let end = this.pos + nextChunk.length; + this.chunk = end > this.range.to ? nextChunk.slice(0, this.range.to - this.pos) : nextChunk; + this.chunkPos = this.pos; + this.chunkOff = 0; + } } - view.contentDOM.addEventListener("beforeinput", read, true); - document.execCommand("indent"); - view.contentDOM.removeEventListener("beforeinput", read, true); - if (!found) - return null; - let anchorNode = found.startContainer, anchorOffset = found.startOffset; - let focusNode = found.endContainer, focusOffset = found.endOffset; - let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor); - // Since such a range doesn't distinguish between anchor and head, - // use a heuristic that flips it around if its end matches the - // current anchor. - if (isEquivalentPosition(curAnchor.node, curAnchor.offset, focusNode, focusOffset)) - [anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset]; - return { anchorNode, anchorOffset, focusNode, focusOffset }; -} - -function applyDOMChange(view, start, end, typeOver) { - let change, newSel; - let sel = view.state.selection.main; - if (start > -1) { - let bounds = view.docView.domBoundsAround(start, end, 0); - if (!bounds || view.state.readOnly) - return; - let { from, to } = bounds; - let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view); - let reader = new DOMReader(selPoints, view.state); - reader.readRange(bounds.startDOM, bounds.endDOM); - let preferredPos = sel.from, preferredSide = null; - // Prefer anchoring to end when Backspace is pressed (or, on - // Android, when something was deleted) - if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 || - browser.android && reader.text.length < to - from) { - preferredPos = sel.to; - preferredSide = "end"; + readNext() { + if (this.chunkOff >= this.chunk.length) { + this.getChunk(); + if (this.chunkOff == this.chunk.length) + return this.next = -1; } - let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide); - if (diff) { - let orig = diff; - // Chrome inserts two newlines when pressing shift-enter at the - // end of a line. This drops one of those. - if (browser.chrome && view.inputState.lastKeyCode == 13 && - diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder) - diff.toB--; - // Strip leading and trailing zero-width spaces from the inserted - // content, to work around widget buffers being moved into text - // nodes by the browser. - while (diff.from < diff.toB && reader.text[diff.from] == "\u200b") { - diff = { from: diff.from + 1, toA: diff.toA, toB: diff.toB }; - selPoints.forEach(p => p.pos -= p.pos > orig.from ? 1 : 0); - } - while (diff.toB > diff.from && reader.text[diff.toB - 1] == "\u200b") { - diff = { from: diff.from, toA: diff.toA, toB: diff.toB - 1 }; - selPoints.forEach(p => p.pos -= p.pos > orig.toB ? 1 : 0); - } - change = { from: from + diff.from, to: from + diff.toA, - insert: state.Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) }; + return this.next = this.chunk.charCodeAt(this.chunkOff); + } + /// Move the stream forward N (defaults to 1) code units. Returns + /// the new value of [`next`](#lr.InputStream.next). + advance(n = 1) { + this.chunkOff += n; + while (this.pos + n >= this.range.to) { + if (this.rangeIndex == this.ranges.length - 1) + return this.setDone(); + n -= this.range.to - this.pos; + this.range = this.ranges[++this.rangeIndex]; + this.pos = this.range.from; } - newSel = selectionFromPoints(selPoints, from); + this.pos += n; + if (this.pos >= this.token.lookAhead) + this.token.lookAhead = this.pos + 1; + return this.readNext(); } - else if (view.hasFocus || !view.state.facet(editable)) { - let domSel = view.observer.selectionRange; - let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView; - let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset || - !contains(view.contentDOM, domSel.focusNode) - ? view.state.selection.main.head - : view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset); - let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset || - !contains(view.contentDOM, domSel.anchorNode) - ? view.state.selection.main.anchor - : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset); - if (head != sel.head || anchor != sel.anchor) - newSel = state.EditorSelection.single(anchor, head); + setDone() { + this.pos = this.chunkPos = this.end; + this.range = this.ranges[this.rangeIndex = this.ranges.length - 1]; + this.chunk = ""; + return this.next = -1; } - if (!change && !newSel) - return; - // Heuristic to notice typing over a selected character - if (!change && typeOver && !sel.empty && newSel && newSel.main.empty) - change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) }; - // If the change is inside the selection and covers most of it, - // assume it is a selection replace (with identical characters at - // the start/end not included in the diff) - else if (change && change.from >= sel.from && change.to <= sel.to && - (change.from != sel.from || change.to != sel.to) && - (sel.to - sel.from) - (change.to - change.from) <= 4) - change = { - from: sel.from, to: sel.to, - insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to)) - }; - if (change) { - let startState = view.state; - if (browser.ios && view.inputState.flushIOSKey(view)) - return; - // Android browsers don't fire reasonable key events for enter, - // backspace, or delete. So this detects changes that look like - // they're caused by those keys, and reinterprets them as key - // events. (Some of these keys are also handled by beforeinput - // events and the pendingAndroidKey mechanism, but that's not - // reliable in all situations.) - if (browser.android && - ((change.from == sel.from && change.to == sel.to && - change.insert.length == 1 && change.insert.lines == 2 && - dispatchKey(view.contentDOM, "Enter", 13)) || - (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 && - dispatchKey(view.contentDOM, "Backspace", 8)) || - (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 && - dispatchKey(view.contentDOM, "Delete", 46)))) - return; - let text = change.insert.toString(); - if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text))) - return; - if (view.inputState.composing >= 0) - view.inputState.composing++; - let tr; - if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 && - (!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) && - view.inputState.composing < 0) { - let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : ""; - let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : ""; - tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after)); + /// @internal + reset(pos, token) { + if (token) { + this.token = token; + token.start = pos; + token.lookAhead = pos + 1; + token.value = token.extended = -1; } else { - let changes = startState.changes(change); - let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength - ? newSel.main : undefined; - // Try to apply a composition change to all cursors - if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 && - change.to <= sel.to && change.to >= sel.to - 10) { - let replaced = view.state.sliceDoc(change.from, change.to); - let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head); - let offset = sel.to - change.to, size = sel.to - sel.from; - tr = startState.changeByRange(range => { - if (range.from == sel.from && range.to == sel.to) - return { changes, range: mainSel || range.map(changes) }; - let to = range.to - offset, from = to - replaced.length; - if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced || - // Unfortunately, there's no way to make multiple - // changes in the same node work without aborting - // composition, so cursors in the composition range are - // ignored. - compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to) - return { range }; - let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to; - return { - changes: rangeChanges, - range: !mainSel ? range.map(rangeChanges) : - state.EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff)) - }; - }); + this.token = nullToken; + } + if (this.pos != pos) { + this.pos = pos; + if (pos == this.end) { + this.setDone(); + return this; } - else { - tr = { - changes, - selection: mainSel && startState.selection.replaceRange(mainSel) - }; + while (pos < this.range.from) + this.range = this.ranges[--this.rangeIndex]; + while (pos >= this.range.to) + this.range = this.ranges[++this.rangeIndex]; + if (pos >= this.chunkPos && pos < this.chunkPos + this.chunk.length) { + this.chunkOff = pos - this.chunkPos; } - } - let userEvent = "input.type"; - if (view.composing) { - userEvent += ".compose"; - if (view.inputState.compositionFirstChange) { - userEvent += ".start"; - view.inputState.compositionFirstChange = false; + else { + this.chunk = ""; + this.chunkOff = 0; } + this.readNext(); } - view.dispatch(tr, { scrollIntoView: true, userEvent }); + return this; } - else if (newSel && !newSel.main.eq(sel)) { - let scrollIntoView = false, userEvent = "select"; - if (view.inputState.lastSelectionTime > Date.now() - 50) { - if (view.inputState.lastSelectionOrigin == "select") - scrollIntoView = true; - userEvent = view.inputState.lastSelectionOrigin; + /// @internal + read(from, to) { + if (from >= this.chunkPos && to <= this.chunkPos + this.chunk.length) + return this.chunk.slice(from - this.chunkPos, to - this.chunkPos); + if (from >= this.range.from && to <= this.range.to) + return this.input.read(from, to); + let result = ""; + for (let r of this.ranges) { + if (r.from >= to) + break; + if (r.to > from) + result += this.input.read(Math.max(r.from, from), Math.min(r.to, to)); } - view.dispatch({ selection: newSel, scrollIntoView, userEvent }); + return result; } } -function findDiff(a, b, preferredPos, preferredSide) { - let minLen = Math.min(a.length, b.length); - let from = 0; - while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from)) - from++; - if (from == minLen && a.length == b.length) - return null; - let toA = a.length, toB = b.length; - while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) { - toA--; - toB--; - } - if (preferredSide == "end") { - let adjust = Math.max(0, from - Math.min(toA, toB)); - preferredPos -= toA + adjust - from; - } - if (toA < from && a.length < b.length) { - let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0; - from -= move; - toB = from + (toB - toA); - toA = from; +/// @internal +class TokenGroup { + constructor(data, id) { + this.data = data; + this.id = id; } - else if (toB < from) { - let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0; - from -= move; - toA = from + (toA - toB); - toB = from; + token(input, stack) { readToken(this.data, input, stack, this.id); } +} +TokenGroup.prototype.contextual = TokenGroup.prototype.fallback = TokenGroup.prototype.extend = false; +/// `@external tokens` declarations in the grammar should resolve to +/// an instance of this class. +class ExternalTokenizer { + /// Create a tokenizer. The first argument is the function that, + /// given an input stream, scans for the types of tokens it + /// recognizes at the stream's position, and calls + /// [`acceptToken`](#lr.InputStream.acceptToken) when it finds + /// one. + constructor( + /// @internal + token, options = {}) { + this.token = token; + this.contextual = !!options.contextual; + this.fallback = !!options.fallback; + this.extend = !!options.extend; } - return { from, toA, toB }; } -function selectionPoints(view) { - let result = []; - if (view.root.activeElement != view.contentDOM) - return result; - let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange; - if (anchorNode) { - result.push(new DOMPoint(anchorNode, anchorOffset)); - if (focusNode != anchorNode || focusOffset != anchorOffset) - result.push(new DOMPoint(focusNode, focusOffset)); +// Tokenizer data is stored a big uint16 array containing, for each +// state: +// +// - A group bitmask, indicating what token groups are reachable from +// this state, so that paths that can only lead to tokens not in +// any of the current groups can be cut off early. +// +// - The position of the end of the state's sequence of accepting +// tokens +// +// - The number of outgoing edges for the state +// +// - The accepting tokens, as (token id, group mask) pairs +// +// - The outgoing edges, as (start character, end character, state +// index) triples, with end character being exclusive +// +// This function interprets that data, running through a stream as +// long as new states with the a matching group mask can be reached, +// and updating `token` when it matches a token. +function readToken(data, input, stack, group) { + let state = 0, groupMask = 1 << group, { parser } = stack.p, { dialect } = parser; + scan: for (;;) { + if ((groupMask & data[state]) == 0) + break; + let accEnd = data[state + 1]; + // Check whether this state can lead to a token in the current group + // Accept tokens in this state, possibly overwriting + // lower-precedence / shorter tokens + for (let i = state + 3; i < accEnd; i += 2) + if ((data[i + 1] & groupMask) > 0) { + let term = data[i]; + if (dialect.allows(term) && + (input.token.value == -1 || input.token.value == term || parser.overrides(term, input.token.value))) { + input.acceptToken(term); + break; + } + } + // Do a binary search on the state's edges + for (let next = input.next, low = 0, high = data[state + 2]; low < high;) { + let mid = (low + high) >> 1; + let index = accEnd + mid + (mid << 1); + let from = data[index], to = data[index + 1]; + if (next < from) + high = mid; + else if (next >= to) + low = mid + 1; + else { + state = data[index + 2]; + input.advance(); + continue scan; + } + } + break; } - return result; } -function selectionFromPoints(points, base) { - if (points.length == 0) - return null; - let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor; - return anchor > -1 && head > -1 ? state.EditorSelection.single(anchor + base, head + base) : null; + +// See lezer-generator/src/encode.ts for comments about the encoding +// used here +function decodeArray(input, Type = Uint16Array) { + if (typeof input != "string") + return input; + let array = null; + for (let pos = 0, out = 0; pos < input.length;) { + let value = 0; + for (;;) { + let next = input.charCodeAt(pos++), stop = false; + if (next == 126 /* BigValCode */) { + value = 65535 /* BigVal */; + break; + } + if (next >= 92 /* Gap2 */) + next--; + if (next >= 34 /* Gap1 */) + next--; + let digit = next - 32 /* Start */; + if (digit >= 46 /* Base */) { + digit -= 46 /* Base */; + stop = true; + } + value += digit; + if (stop) + break; + value *= 46 /* Base */; + } + if (array) + array[out++] = value; + else + array = new Type(value); + } + return array; } -// The editor's update state machine looks something like this: -// -// Idle → Updating ⇆ Idle (unchecked) → Measuring → Idle -// ↑ ↓ -// Updating (measure) -// -// The difference between 'Idle' and 'Idle (unchecked)' lies in -// whether a layout check has been scheduled. A regular update through -// the `update` method updates the DOM in a write-only fashion, and -// relies on a check (scheduled with `requestAnimationFrame`) to make -// sure everything is where it should be and the viewport covers the -// visible code. That check continues to measure and then optionally -// update until it reaches a coherent state. -/** -An editor view represents the editor's user interface. It holds -the editable DOM surface, and possibly other elements such as the -line number gutter. It handles events and dispatches state -transactions for editing actions. -*/ -class EditorView { - /** - Construct a new view. You'll usually want to put `view.dom` into - your document after creating a view, so that the user can see - it. - */ - constructor( - /** - Initialization options. - */ - config = {}) { - this.plugins = []; - this.pluginMap = new Map; - this.editorAttrs = {}; - this.contentAttrs = {}; - this.bidiCache = []; - this.destroyed = false; - /** - @internal - */ - this.updateState = 2 /* Updating */; - /** - @internal - */ - this.measureScheduled = -1; - /** - @internal - */ - this.measureRequests = []; - this.contentDOM = document.createElement("div"); - this.scrollDOM = document.createElement("div"); - this.scrollDOM.tabIndex = -1; - this.scrollDOM.className = "cm-scroller"; - this.scrollDOM.appendChild(this.contentDOM); - this.announceDOM = document.createElement("div"); - this.announceDOM.style.cssText = "position: absolute; top: -10000px"; - this.announceDOM.setAttribute("aria-live", "polite"); - this.dom = document.createElement("div"); - this.dom.appendChild(this.announceDOM); - this.dom.appendChild(this.scrollDOM); - this._dispatch = config.dispatch || ((tr) => this.update([tr])); - this.dispatch = this.dispatch.bind(this); - this.root = (config.root || getRoot(config.parent) || document); - this.viewState = new ViewState(config.state || state.EditorState.create()); - this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec)); - for (let plugin of this.plugins) - plugin.update(this); - this.observer = new DOMObserver(this, (from, to, typeOver) => { - applyDOMChange(this, from, to, typeOver); - }, event => { - this.inputState.runScrollHandlers(this, event); - if (this.observer.intersecting) - this.measure(); - }); - this.inputState = new InputState(this); - this.docView = new DocView(this); - this.mountStyles(); - this.updateAttrs(); - this.updateState = 0 /* Idle */; - ensureGlobalHandler(); - this.requestMeasure(); - if (config.parent) - config.parent.appendChild(this.dom); +// FIXME find some way to reduce recovery work done when the input +// doesn't match the grammar at all. +// Environment variable used to control console output +const verbose = typeof process != "undefined" && /\bparse\b/.test(process.env.LOG); +let stackIDs = null; +var Safety; +(function (Safety) { + Safety[Safety["Margin"] = 25] = "Margin"; +})(Safety || (Safety = {})); +function cutAt(tree, pos, side) { + let cursor = tree.fullCursor(); + cursor.moveTo(pos); + for (;;) { + if (!(side < 0 ? cursor.childBefore(pos) : cursor.childAfter(pos))) + for (;;) { + if ((side < 0 ? cursor.to < pos : cursor.from > pos) && !cursor.type.isError) + return side < 0 ? Math.max(0, Math.min(cursor.to - 1, pos - 25 /* Margin */)) + : Math.min(tree.length, Math.max(cursor.from + 1, pos + 25 /* Margin */)); + if (side < 0 ? cursor.prevSibling() : cursor.nextSibling()) + break; + if (!cursor.parent()) + return side < 0 ? 0 : tree.length; + } } - /** - The current editor state. - */ - get state() { return this.viewState.state; } - /** - To be able to display large documents without consuming too much - memory or overloading the browser, CodeMirror only draws the - code that is visible (plus a margin around it) to the DOM. This - property tells you the extent of the current drawn viewport, in - document positions. - */ - get viewport() { return this.viewState.viewport; } - /** - When there are, for example, large collapsed ranges in the - viewport, its size can be a lot bigger than the actual visible - content. Thus, if you are doing something like styling the - content in the viewport, it is preferable to only do so for - these ranges, which are the subset of the viewport that is - actually drawn. - */ - get visibleRanges() { return this.viewState.visibleRanges; } - /** - Returns false when the editor is entirely scrolled out of view - or otherwise hidden. - */ - get inView() { return this.viewState.inView; } - /** - Indicates whether the user is currently composing text via - [IME](https://en.wikipedia.org/wiki/Input_method). - */ - get composing() { return this.inputState.composing > 0; } - dispatch(...input) { - this._dispatch(input.length == 1 && input[0] instanceof state.Transaction ? input[0] - : this.state.update(...input)); +} +class FragmentCursor { + constructor(fragments, nodeSet) { + this.fragments = fragments; + this.nodeSet = nodeSet; + this.i = 0; + this.fragment = null; + this.safeFrom = -1; + this.safeTo = -1; + this.trees = []; + this.start = []; + this.index = []; + this.nextFragment(); } - /** - Update the view for the given array of transactions. This will - update the visible document and selection to match the state - produced by the transactions, and notify view plugins of the - change. You should usually call - [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead, which uses this - as a primitive. - */ - update(transactions) { - if (this.updateState != 0 /* Idle */) - throw new Error("Calls to EditorView.update are not allowed while an update is in progress"); - let redrawn = false, update; - let state$1 = this.state; - for (let tr of transactions) { - if (tr.startState != state$1) - throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state."); - state$1 = tr.state; + nextFragment() { + let fr = this.fragment = this.i == this.fragments.length ? null : this.fragments[this.i++]; + if (fr) { + this.safeFrom = fr.openStart ? cutAt(fr.tree, fr.from + fr.offset, 1) - fr.offset : fr.from; + this.safeTo = fr.openEnd ? cutAt(fr.tree, fr.to + fr.offset, -1) - fr.offset : fr.to; + while (this.trees.length) { + this.trees.pop(); + this.start.pop(); + this.index.pop(); + } + this.trees.push(fr.tree); + this.start.push(-fr.offset); + this.index.push(0); + this.nextStart = this.safeFrom; } - if (this.destroyed) { - this.viewState.state = state$1; - return; + else { + this.nextStart = 1e9; } - // When the phrases change, redraw the editor - if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases)) - return this.setState(state$1); - update = new ViewUpdate(this, state$1, transactions); - let scrollTarget = this.viewState.scrollTarget; - try { - this.updateState = 2 /* Updating */; - for (let tr of transactions) { - if (scrollTarget) - scrollTarget = scrollTarget.map(tr.changes); - if (tr.scrollIntoView) { - let { main } = tr.state.selection; - scrollTarget = new ScrollTarget(main.empty ? main : state.EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1)); + } + // `pos` must be >= any previously given `pos` for this cursor + nodeAt(pos) { + if (pos < this.nextStart) + return null; + while (this.fragment && this.safeTo <= pos) + this.nextFragment(); + if (!this.fragment) + return null; + for (;;) { + let last = this.trees.length - 1; + if (last < 0) { // End of tree + this.nextFragment(); + return null; + } + let top = this.trees[last], index = this.index[last]; + if (index == top.children.length) { + this.trees.pop(); + this.start.pop(); + this.index.pop(); + continue; + } + let next = top.children[index]; + let start = this.start[last] + top.positions[index]; + if (start > pos) { + this.nextStart = start; + return null; + } + if (next instanceof common.Tree) { + if (start == pos) { + if (start < this.safeFrom) + return null; + let end = start + next.length; + if (end <= this.safeTo) { + let lookAhead = next.prop(common.NodeProp.lookAhead); + if (!lookAhead || end + lookAhead < this.fragment.to) + return next; + } } - for (let e of tr.effects) { - if (e.is(scrollTo)) - scrollTarget = new ScrollTarget(e.value); - else if (e.is(centerOn)) - scrollTarget = new ScrollTarget(e.value, "center"); - else if (e.is(scrollIntoView)) - scrollTarget = e.value; + this.index[last]++; + if (start + next.length >= Math.max(this.safeFrom, pos)) { // Enter this node + this.trees.push(next); + this.start.push(start); + this.index.push(0); } } - this.viewState.update(update, scrollTarget); - this.bidiCache = CachedOrder.update(this.bidiCache, update.changes); - if (!update.empty) { - this.updatePlugins(update); - this.inputState.update(update); + else { + this.index[last]++; + this.nextStart = start + next.length; } - redrawn = this.docView.update(update); - if (this.state.facet(styleModule) != this.styleModules) - this.mountStyles(); - this.updateAttrs(); - this.showAnnouncements(transactions); - this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer"))); } - finally { - this.updateState = 0 /* Idle */; - } - if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc) - this.requestMeasure(); - if (!update.empty) - for (let listener of this.state.facet(updateListener)) - listener(update); } - /** - Reset the view to the given state. (This will cause the entire - document to be redrawn and all view plugins to be reinitialized, - so you should probably only use it when the new state isn't - derived from the old state. Otherwise, use - [`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead.) - */ - setState(newState) { - if (this.updateState != 0 /* Idle */) - throw new Error("Calls to EditorView.setState are not allowed while an update is in progress"); - if (this.destroyed) { - this.viewState.state = newState; - return; - } - this.updateState = 2 /* Updating */; - let hadFocus = this.hasFocus; - try { - for (let plugin of this.plugins) - plugin.destroy(this); - this.viewState = new ViewState(newState); - this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec)); - this.pluginMap.clear(); - for (let plugin of this.plugins) - plugin.update(this); - this.docView = new DocView(this); - this.inputState.ensureHandlers(this); - this.mountStyles(); - this.updateAttrs(); - this.bidiCache = []; +} +class TokenCache { + constructor(parser, stream) { + this.stream = stream; + this.tokens = []; + this.mainToken = null; + this.actions = []; + this.tokens = parser.tokenizers.map(_ => new CachedToken); + } + getActions(stack) { + let actionIndex = 0; + let main = null; + let { parser } = stack.p, { tokenizers } = parser; + let mask = parser.stateSlot(stack.state, 3 /* TokenizerMask */); + let context = stack.curContext ? stack.curContext.hash : 0; + let lookAhead = 0; + for (let i = 0; i < tokenizers.length; i++) { + if (((1 << i) & mask) == 0) + continue; + let tokenizer = tokenizers[i], token = this.tokens[i]; + if (main && !tokenizer.fallback) + continue; + if (tokenizer.contextual || token.start != stack.pos || token.mask != mask || token.context != context) { + this.updateCachedToken(token, tokenizer, stack); + token.mask = mask; + token.context = context; + } + if (token.lookAhead > token.end + 25 /* Margin */) + lookAhead = Math.max(token.lookAhead, lookAhead); + if (token.value != 0 /* Err */) { + let startIndex = actionIndex; + if (token.extended > -1) + actionIndex = this.addActions(stack, token.extended, token.end, actionIndex); + actionIndex = this.addActions(stack, token.value, token.end, actionIndex); + if (!tokenizer.extend) { + main = token; + if (actionIndex > startIndex) + break; + } + } } - finally { - this.updateState = 0 /* Idle */; + while (this.actions.length > actionIndex) + this.actions.pop(); + if (lookAhead) + stack.setLookAhead(lookAhead); + if (!main && stack.pos == this.stream.end) { + main = new CachedToken; + main.value = stack.p.parser.eofTerm; + main.start = main.end = stack.pos; + actionIndex = this.addActions(stack, main.value, main.end, actionIndex); } - if (hadFocus) - this.focus(); - this.requestMeasure(); + this.mainToken = main; + return this.actions; } - updatePlugins(update) { - let prevSpecs = update.startState.facet(viewPlugin), specs = update.state.facet(viewPlugin); - if (prevSpecs != specs) { - let newPlugins = []; - for (let spec of specs) { - let found = prevSpecs.indexOf(spec); - if (found < 0) { - newPlugins.push(new PluginInstance(spec)); - } - else { - let plugin = this.plugins[found]; - plugin.mustUpdate = update; - newPlugins.push(plugin); + getMainToken(stack) { + if (this.mainToken) + return this.mainToken; + let main = new CachedToken, { pos, p } = stack; + main.start = pos; + main.end = Math.min(pos + 1, p.stream.end); + main.value = pos == p.stream.end ? p.parser.eofTerm : 0 /* Err */; + return main; + } + updateCachedToken(token, tokenizer, stack) { + tokenizer.token(this.stream.reset(stack.pos, token), stack); + if (token.value > -1) { + let { parser } = stack.p; + for (let i = 0; i < parser.specialized.length; i++) + if (parser.specialized[i] == token.value) { + let result = parser.specializers[i](this.stream.read(token.start, token.end), stack); + if (result >= 0 && stack.p.parser.dialect.allows(result >> 1)) { + if ((result & 1) == 0 /* Specialize */) + token.value = result >> 1; + else + token.extended = result >> 1; + break; + } } - } - for (let plugin of this.plugins) - if (plugin.mustUpdate != update) - plugin.destroy(this); - this.plugins = newPlugins; - this.pluginMap.clear(); - this.inputState.ensureHandlers(this); } else { - for (let p of this.plugins) - p.mustUpdate = update; + token.value = 0 /* Err */; + token.end = Math.min(stack.p.stream.end, stack.pos + 1); } - for (let i = 0; i < this.plugins.length; i++) - this.plugins[i].update(this); } - /** - @internal - */ - measure(flush = true) { - if (this.destroyed) - return; - if (this.measureScheduled > -1) - cancelAnimationFrame(this.measureScheduled); - this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame - if (flush) - this.observer.flush(); - let updated = null; - try { - for (let i = 0;; i++) { - this.updateState = 1 /* Measuring */; - let oldViewport = this.viewport; - let changed = this.viewState.measure(this); - if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null) - break; - if (i > 5) { - console.warn(this.measureRequests.length - ? "Measure loop restarted more than 5 times" - : "Viewport failed to stabilize"); - break; - } - let measuring = []; - // Only run measure requests in this cycle when the viewport didn't change - if (!(changed & 4 /* Viewport */)) - [this.measureRequests, measuring] = [measuring, this.measureRequests]; - let measured = measuring.map(m => { - try { - return m.read(this); - } - catch (e) { - logException(this.state, e); - return BadMeasure; + putAction(action, token, end, index) { + // Don't add duplicate actions + for (let i = 0; i < index; i += 3) + if (this.actions[i] == action) + return index; + this.actions[index++] = action; + this.actions[index++] = token; + this.actions[index++] = end; + return index; + } + addActions(stack, token, end, index) { + let { state } = stack, { parser } = stack.p, { data } = parser; + for (let set = 0; set < 2; set++) { + for (let i = parser.stateSlot(state, set ? 2 /* Skip */ : 1 /* Actions */);; i += 3) { + if (data[i] == 65535 /* End */) { + if (data[i + 1] == 1 /* Next */) { + i = pair(data, i + 2); } - }); - let update = new ViewUpdate(this, this.state), redrawn = false, scrolled = false; - update.flags |= changed; - if (!updated) - updated = update; - else - updated.flags |= changed; - this.updateState = 2 /* Updating */; - if (!update.empty) { - this.updatePlugins(update); - this.inputState.update(update); - this.updateAttrs(); - redrawn = this.docView.update(update); - } - for (let i = 0; i < measuring.length; i++) - if (measured[i] != BadMeasure) { - try { - let m = measuring[i]; - if (m.write) - m.write(measured[i], this); - } - catch (e) { - logException(this.state, e); - } + else { + if (index == 0 && data[i + 1] == 2 /* Other */) + index = this.putAction(pair(data, i + 1), token, end, index); + break; } - if (this.viewState.scrollTarget) { - this.docView.scrollIntoView(this.viewState.scrollTarget); - this.viewState.scrollTarget = null; - scrolled = true; } - if (redrawn) - this.docView.updateSelection(true); - if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && - !scrolled && this.measureRequests.length == 0) - break; + if (data[i] == token) + index = this.putAction(pair(data, i + 1), token, end, index); } } - finally { - this.updateState = 0 /* Idle */; - this.measureScheduled = -1; - } - if (updated && !updated.empty) - for (let listener of this.state.facet(updateListener)) - listener(updated); + return index; } - /** - Get the CSS classes for the currently active editor themes. - */ - get themeClasses() { - return baseThemeID + " " + - (this.state.facet(darkTheme) ? baseDarkID : baseLightID) + " " + - this.state.facet(theme); +} +var Rec; +(function (Rec) { + Rec[Rec["Distance"] = 5] = "Distance"; + Rec[Rec["MaxRemainingPerStep"] = 3] = "MaxRemainingPerStep"; + // When two stacks have been running independently long enough to + // add this many elements to their buffers, prune one. + Rec[Rec["MinBufferLengthPrune"] = 500] = "MinBufferLengthPrune"; + Rec[Rec["ForceReduceLimit"] = 10] = "ForceReduceLimit"; + // Once a stack reaches this depth (in .stack.length) force-reduce + // it back to CutTo to avoid creating trees that overflow the stack + // on recursive traversal. + Rec[Rec["CutDepth"] = 15000] = "CutDepth"; + Rec[Rec["CutTo"] = 9000] = "CutTo"; +})(Rec || (Rec = {})); +class Parse { + constructor(parser, input, fragments, ranges) { + this.parser = parser; + this.input = input; + this.ranges = ranges; + this.recovering = 0; + this.nextStackID = 0x2654; // ♔, ♕, ♖, ♗, ♘, ♙, ♠, ♡, ♢, ♣, ♤, ♥, ♦, ♧ + this.minStackPos = 0; + this.reused = []; + this.stoppedAt = null; + this.stream = new InputStream(input, ranges); + this.tokens = new TokenCache(parser, this.stream); + this.topTerm = parser.top[1]; + let { from } = ranges[0]; + this.stacks = [Stack.start(this, parser.top[0], from)]; + this.fragments = fragments.length && this.stream.end - from > parser.bufferLength * 4 + ? new FragmentCursor(fragments, parser.nodeSet) : null; } - updateAttrs() { - let editorAttrs = attrsFromFacet(this, editorAttributes, { - class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses - }); - let contentAttrs = { - spellcheck: "false", - autocorrect: "off", - autocapitalize: "off", - translate: "no", - contenteditable: !this.state.facet(editable) ? "false" : "true", - class: "cm-content", - style: `${browser.tabSize}: ${this.state.tabSize}`, - role: "textbox", - "aria-multiline": "true" - }; - if (this.state.readOnly) - contentAttrs["aria-readonly"] = "true"; - attrsFromFacet(this, contentAttributes, contentAttrs); - this.observer.ignore(() => { - updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs); - updateAttrs(this.dom, this.editorAttrs, editorAttrs); - }); - this.editorAttrs = editorAttrs; - this.contentAttrs = contentAttrs; + get parsedPos() { + return this.minStackPos; } - showAnnouncements(trs) { - let first = true; - for (let tr of trs) - for (let effect of tr.effects) - if (effect.is(EditorView.announce)) { - if (first) - this.announceDOM.textContent = ""; - first = false; - let div = this.announceDOM.appendChild(document.createElement("div")); - div.textContent = effect.value; + // Move the parser forward. This will process all parse stacks at + // `this.pos` and try to advance them to a further position. If no + // stack for such a position is found, it'll start error-recovery. + // + // When the parse is finished, this will return a syntax tree. When + // not, it returns `null`. + advance() { + let stacks = this.stacks, pos = this.minStackPos; + // This will hold stacks beyond `pos`. + let newStacks = this.stacks = []; + let stopped, stoppedTokens; + // Keep advancing any stacks at `pos` until they either move + // forward or can't be advanced. Gather stacks that can't be + // advanced further in `stopped`. + for (let i = 0; i < stacks.length; i++) { + let stack = stacks[i]; + for (;;) { + this.tokens.mainToken = null; + if (stack.pos > pos) { + newStacks.push(stack); } - } - mountStyles() { - this.styleModules = this.state.facet(styleModule); - styleMod.StyleModule.mount(this.root, this.styleModules.concat(baseTheme).reverse()); - } - readMeasured() { - if (this.updateState == 2 /* Updating */) - throw new Error("Reading the editor layout isn't allowed during an update"); - if (this.updateState == 0 /* Idle */ && this.measureScheduled > -1) - this.measure(false); - } - /** - Schedule a layout measurement, optionally providing callbacks to - do custom DOM measuring followed by a DOM write phase. Using - this is preferable reading DOM layout directly from, for - example, an event handler, because it'll make sure measuring and - drawing done by other components is synchronized, avoiding - unnecessary DOM layout computations. - */ - requestMeasure(request) { - if (this.measureScheduled < 0) - this.measureScheduled = requestAnimationFrame(() => this.measure()); - if (request) { - if (request.key != null) - for (let i = 0; i < this.measureRequests.length; i++) { - if (this.measureRequests[i].key === request.key) { - this.measureRequests[i] = request; - return; + else if (this.advanceStack(stack, newStacks, stacks)) { + continue; + } + else { + if (!stopped) { + stopped = []; + stoppedTokens = []; } + stopped.push(stack); + let tok = this.tokens.getMainToken(stack); + stoppedTokens.push(tok.value, tok.end); } - this.measureRequests.push(request); + break; + } + } + if (!newStacks.length) { + let finished = stopped && findFinished(stopped); + if (finished) + return this.stackToTree(finished); + if (this.parser.strict) { + if (verbose && stopped) + console.log("Stuck with token " + (this.tokens.mainToken ? this.parser.getName(this.tokens.mainToken.value) : "none")); + throw new SyntaxError("No parse at " + pos); + } + if (!this.recovering) + this.recovering = 5 /* Distance */; + } + if (this.recovering && stopped) { + let finished = this.stoppedAt != null && stopped[0].pos > this.stoppedAt ? stopped[0] + : this.runRecovery(stopped, stoppedTokens, newStacks); + if (finished) + return this.stackToTree(finished.forceAll()); + } + if (this.recovering) { + let maxRemaining = this.recovering == 1 ? 1 : this.recovering * 3 /* MaxRemainingPerStep */; + if (newStacks.length > maxRemaining) { + newStacks.sort((a, b) => b.score - a.score); + while (newStacks.length > maxRemaining) + newStacks.pop(); + } + if (newStacks.some(s => s.reducePos > pos)) + this.recovering--; + } + else if (newStacks.length > 1) { + // Prune stacks that are in the same state, or that have been + // running without splitting for a while, to avoid getting stuck + // with multiple successful stacks running endlessly on. + outer: for (let i = 0; i < newStacks.length - 1; i++) { + let stack = newStacks[i]; + for (let j = i + 1; j < newStacks.length; j++) { + let other = newStacks[j]; + if (stack.sameState(other) || + stack.buffer.length > 500 /* MinBufferLengthPrune */ && other.buffer.length > 500 /* MinBufferLengthPrune */) { + if (((stack.score - other.score) || (stack.buffer.length - other.buffer.length)) > 0) { + newStacks.splice(j--, 1); + } + else { + newStacks.splice(i--, 1); + continue outer; + } + } + } + } } + this.minStackPos = newStacks[0].pos; + for (let i = 1; i < newStacks.length; i++) + if (newStacks[i].pos < this.minStackPos) + this.minStackPos = newStacks[i].pos; + return null; } - /** - Collect all values provided by the active plugins for a given - field. - */ - pluginField(field) { - let result = []; - for (let plugin of this.plugins) - plugin.update(this).takeField(field, result); - return result; - } - /** - Get the value of a specific plugin, if present. Note that - plugins that crash can be dropped from a view, so even when you - know you registered a given plugin, it is recommended to check - the return value of this method. - */ - plugin(plugin) { - let known = this.pluginMap.get(plugin); - if (known === undefined || known && known.spec != plugin) - this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null); - return known && known.update(this).value; - } - /** - The top position of the document, in screen coordinates. This - may be negative when the editor is scrolled down. Points - directly to the top of the first line, not above the padding. - */ - get documentTop() { - return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop; - } - /** - Reports the padding above and below the document. - */ - get documentPadding() { - return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom }; - } - /** - Find the line or block widget at the given vertical position. - - By default, this position is interpreted as a screen position, - meaning `docTop` is set to the DOM top position of the editor - content (forcing a layout). You can pass a different `docTop` - value—for example 0 to interpret `height` as a document-relative - position, or a precomputed document top - (`view.contentDOM.getBoundingClientRect().top`) to limit layout - queries. - - *Deprecated: use `elementAtHeight` instead.* - */ - blockAtHeight(height, docTop) { - let top = ensureTop(docTop, this); - return this.elementAtHeight(height - top).moveY(top); - } - /** - Find the text line or block widget at the given vertical - position (which is interpreted as relative to the [top of the - document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop) - */ - elementAtHeight(height) { - this.readMeasured(); - return this.viewState.elementAtHeight(height); + stopAt(pos) { + if (this.stoppedAt != null && this.stoppedAt < pos) + throw new RangeError("Can't move stoppedAt forward"); + this.stoppedAt = pos; } - /** - Find information for the visual line (see - [`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given - vertical position. The resulting block info might hold another - array of block info structs in its `type` field if this line - consists of more than one block. - - Defaults to treating `height` as a screen position. See - [`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the - interpretation of the `docTop` parameter. - - *Deprecated: use `lineBlockAtHeight` instead.* - */ - visualLineAtHeight(height, docTop) { - let top = ensureTop(docTop, this); - return this.lineBlockAtHeight(height - top).moveY(top); + // Returns an updated version of the given stack, or null if the + // stack can't advance normally. When `split` and `stacks` are + // given, stacks split off by ambiguous operations will be pushed to + // `split`, or added to `stacks` if they move `pos` forward. + advanceStack(stack, stacks, split) { + let start = stack.pos, { parser } = this; + let base = verbose ? this.stackID(stack) + " -> " : ""; + if (this.stoppedAt != null && start > this.stoppedAt) + return stack.forceReduce() ? stack : null; + if (this.fragments) { + let strictCx = stack.curContext && stack.curContext.tracker.strict, cxHash = strictCx ? stack.curContext.hash : 0; + for (let cached = this.fragments.nodeAt(start); cached;) { + let match = this.parser.nodeSet.types[cached.type.id] == cached.type ? parser.getGoto(stack.state, cached.type.id) : -1; + if (match > -1 && cached.length && (!strictCx || (cached.prop(common.NodeProp.contextHash) || 0) == cxHash)) { + stack.useNode(cached, match); + if (verbose) + console.log(base + this.stackID(stack) + ` (via reuse of ${parser.getName(cached.type.id)})`); + return true; + } + if (!(cached instanceof common.Tree) || cached.children.length == 0 || cached.positions[0] > 0) + break; + let inner = cached.children[0]; + if (inner instanceof common.Tree && cached.positions[0] == 0) + cached = inner; + else + break; + } + } + let defaultReduce = parser.stateSlot(stack.state, 4 /* DefaultReduce */); + if (defaultReduce > 0) { + stack.reduce(defaultReduce); + if (verbose) + console.log(base + this.stackID(stack) + ` (via always-reduce ${parser.getName(defaultReduce & 65535 /* ValueMask */)})`); + return true; + } + if (stack.stack.length >= 15000 /* CutDepth */) { + while (stack.stack.length > 9000 /* CutTo */ && stack.forceReduce()) { } + } + let actions = this.tokens.getActions(stack); + for (let i = 0; i < actions.length;) { + let action = actions[i++], term = actions[i++], end = actions[i++]; + let last = i == actions.length || !split; + let localStack = last ? stack : stack.split(); + localStack.apply(action, term, end); + if (verbose) + console.log(base + this.stackID(localStack) + ` (via ${(action & 65536 /* ReduceFlag */) == 0 ? "shift" + : `reduce of ${parser.getName(action & 65535 /* ValueMask */)}`} for ${parser.getName(term)} @ ${start}${localStack == stack ? "" : ", split"})`); + if (last) + return true; + else if (localStack.pos > start) + stacks.push(localStack); + else + split.push(localStack); + } + return false; } - /** - Find the line block (see - [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given - height. - */ - lineBlockAtHeight(height) { - this.readMeasured(); - return this.viewState.lineBlockAtHeight(height); + // Advance a given stack forward as far as it will go. Returns the + // (possibly updated) stack if it got stuck, or null if it moved + // forward and was given to `pushStackDedup`. + advanceFully(stack, newStacks) { + let pos = stack.pos; + for (;;) { + if (!this.advanceStack(stack, null, null)) + return false; + if (stack.pos > pos) { + pushStackDedup(stack, newStacks); + return true; + } + } } - /** - Iterate over the height information of the visual lines in the - viewport. The heights of lines are reported relative to the - given document top, which defaults to the screen position of the - document (forcing a layout). - - *Deprecated: use `viewportLineBlocks` instead.* - */ - viewportLines(f, docTop) { - let top = ensureTop(docTop, this); - for (let line of this.viewportLineBlocks) - f(line.moveY(top)); + runRecovery(stacks, tokens, newStacks) { + let finished = null, restarted = false; + for (let i = 0; i < stacks.length; i++) { + let stack = stacks[i], token = tokens[i << 1], tokenEnd = tokens[(i << 1) + 1]; + let base = verbose ? this.stackID(stack) + " -> " : ""; + if (stack.deadEnd) { + if (restarted) + continue; + restarted = true; + stack.restart(); + if (verbose) + console.log(base + this.stackID(stack) + " (restarted)"); + let done = this.advanceFully(stack, newStacks); + if (done) + continue; + } + let force = stack.split(), forceBase = base; + for (let j = 0; force.forceReduce() && j < 10 /* ForceReduceLimit */; j++) { + if (verbose) + console.log(forceBase + this.stackID(force) + " (via force-reduce)"); + let done = this.advanceFully(force, newStacks); + if (done) + break; + if (verbose) + forceBase = this.stackID(force) + " -> "; + } + for (let insert of stack.recoverByInsert(token)) { + if (verbose) + console.log(base + this.stackID(insert) + " (via recover-insert)"); + this.advanceFully(insert, newStacks); + } + if (this.stream.end > stack.pos) { + if (tokenEnd == stack.pos) { + tokenEnd++; + token = 0 /* Err */; + } + stack.recoverByDelete(token, tokenEnd); + if (verbose) + console.log(base + this.stackID(stack) + ` (via recover-delete ${this.parser.getName(token)})`); + pushStackDedup(stack, newStacks); + } + else if (!finished || finished.score < stack.score) { + finished = stack; + } + } + return finished; } - /** - Get the extent and vertical position of all [line - blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions - are relative to the [top of the - document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop); - */ - get viewportLineBlocks() { - return this.viewState.viewportLines; + // Convert the stack's buffer to a syntax tree. + stackToTree(stack) { + stack.close(); + return common.Tree.build({ buffer: StackBufferCursor.create(stack), + nodeSet: this.parser.nodeSet, + topID: this.topTerm, + maxBufferLength: this.parser.bufferLength, + reused: this.reused, + start: this.ranges[0].from, + length: stack.pos - this.ranges[0].from, + minRepeatType: this.parser.minRepeatTerm }); } - /** - Find the extent and height of the visual line (a range delimited - on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) - line breaks, or the start/end of the document) at the given position. - - Vertical positions are computed relative to the `docTop` - argument, which defaults to 0 for this method. You can pass - `view.contentDOM.getBoundingClientRect().top` here to get screen - coordinates. - - *Deprecated: use `lineBlockAt` instead.* - */ - visualLineAt(pos, docTop = 0) { - return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop); + stackID(stack) { + let id = (stackIDs || (stackIDs = new WeakMap)).get(stack); + if (!id) + stackIDs.set(stack, id = String.fromCodePoint(this.nextStackID++)); + return id + stack; } - /** - Find the line block around the given document position. A line - block is a range delimited on both sides by either a - non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) line breaks, or the - start/end of the document. It will usually just hold a line of - text, but may be broken into multiple textblocks by block - widgets. - */ - lineBlockAt(pos) { - return this.viewState.lineBlockAt(pos); +} +function pushStackDedup(stack, newStacks) { + for (let i = 0; i < newStacks.length; i++) { + let other = newStacks[i]; + if (other.pos == stack.pos && other.sameState(stack)) { + if (newStacks[i].score < stack.score) + newStacks[i] = stack; + return; + } } - /** - The editor's total content height. - */ - get contentHeight() { - return this.viewState.contentHeight; + newStacks.push(stack); +} +class Dialect { + constructor(source, flags, disabled) { + this.source = source; + this.flags = flags; + this.disabled = disabled; } - /** - Move a cursor position by [grapheme - cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak). `forward` determines whether - the motion is away from the line start, or towards it. Motion in - bidirectional text is in visual order, in the editor's [text - direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). When the start - position was the last one on the line, the returned position - will be across the line break. If there is no further line, the - original position is returned. - - By default, this method moves over a single cluster. The - optional `by` argument can be used to move across more. It will - be called with the first cluster as argument, and should return - a predicate that determines, for each subsequent cluster, - whether it should also be moved over. - */ - moveByChar(start, forward, by) { - return skipAtoms(this, start, moveByChar(this, start, forward, by)); + allows(term) { return !this.disabled || this.disabled[term] == 0; } +} +const id = x => x; +/// Context trackers are used to track stateful context (such as +/// indentation in the Python grammar, or parent elements in the XML +/// grammar) needed by external tokenizers. You declare them in a +/// grammar file as `@context exportName from "module"`. +/// +/// Context values should be immutable, and can be updated (replaced) +/// on shift or reduce actions. +/// +/// The export used in a `@context` declaration should be of this +/// type. +class ContextTracker { + /// Define a context tracker. + constructor(spec) { + this.start = spec.start; + this.shift = spec.shift || id; + this.reduce = spec.reduce || id; + this.reuse = spec.reuse || id; + this.hash = spec.hash || (() => 0); + this.strict = spec.strict !== false; } - /** - Move a cursor position across the next group of either - [letters](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) or non-letter - non-whitespace characters. - */ - moveByGroup(start, forward) { - return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial))); +} +/// A parser holds the parse tables for a given grammar, as generated +/// by `lezer-generator`. +class LRParser extends common.Parser { + /// @internal + constructor(spec) { + super(); + /// @internal + this.wrappers = []; + if (spec.version != 13 /* Version */) + throw new RangeError(`Parser version (${spec.version}) doesn't match runtime version (${13 /* Version */})`); + let nodeNames = spec.nodeNames.split(" "); + this.minRepeatTerm = nodeNames.length; + for (let i = 0; i < spec.repeatNodeCount; i++) + nodeNames.push(""); + let topTerms = Object.keys(spec.topRules).map(r => spec.topRules[r][1]); + let nodeProps = []; + for (let i = 0; i < nodeNames.length; i++) + nodeProps.push([]); + function setProp(nodeID, prop, value) { + nodeProps[nodeID].push([prop, prop.deserialize(String(value))]); + } + if (spec.nodeProps) + for (let propSpec of spec.nodeProps) { + let prop = propSpec[0]; + for (let i = 1; i < propSpec.length;) { + let next = propSpec[i++]; + if (next >= 0) { + setProp(next, prop, propSpec[i++]); + } + else { + let value = propSpec[i + -next]; + for (let j = -next; j > 0; j--) + setProp(propSpec[i++], prop, value); + i++; + } + } + } + this.nodeSet = new common.NodeSet(nodeNames.map((name, i) => common.NodeType.define({ + name: i >= this.minRepeatTerm ? undefined : name, + id: i, + props: nodeProps[i], + top: topTerms.indexOf(i) > -1, + error: i == 0, + skipped: spec.skippedNodes && spec.skippedNodes.indexOf(i) > -1 + }))); + this.strict = false; + this.bufferLength = common.DefaultBufferLength; + let tokenArray = decodeArray(spec.tokenData); + this.context = spec.context; + this.specialized = new Uint16Array(spec.specialized ? spec.specialized.length : 0); + this.specializers = []; + if (spec.specialized) + for (let i = 0; i < spec.specialized.length; i++) { + this.specialized[i] = spec.specialized[i].term; + this.specializers[i] = spec.specialized[i].get; + } + this.states = decodeArray(spec.states, Uint32Array); + this.data = decodeArray(spec.stateData); + this.goto = decodeArray(spec.goto); + this.maxTerm = spec.maxTerm; + this.tokenizers = spec.tokenizers.map(value => typeof value == "number" ? new TokenGroup(tokenArray, value) : value); + this.topRules = spec.topRules; + this.dialects = spec.dialects || {}; + this.dynamicPrecedences = spec.dynamicPrecedences || null; + this.tokenPrecTable = spec.tokenPrec; + this.termNames = spec.termNames || null; + this.maxNode = this.nodeSet.types.length - 1; + this.dialect = this.parseDialect(); + this.top = this.topRules[Object.keys(this.topRules)[0]]; } - /** - Move to the next line boundary in the given direction. If - `includeWrap` is true, line wrapping is on, and there is a - further wrap point on the current line, the wrap point will be - returned. Otherwise this function will return the start or end - of the line. - */ - moveToLineBoundary(start, forward, includeWrap = true) { - return moveToLineBoundary(this, start, forward, includeWrap); + createParse(input, fragments, ranges) { + let parse = new Parse(this, input, fragments, ranges); + for (let w of this.wrappers) + parse = w(parse, input, fragments, ranges); + return parse; } - /** - Move a cursor position vertically. When `distance` isn't given, - it defaults to moving to the next line (including wrapped - lines). Otherwise, `distance` should provide a positive distance - in pixels. - - When `start` has a - [`goalColumn`](https://codemirror.net/6/docs/ref/#state.SelectionRange.goalColumn), the vertical - motion will use that as a target horizontal position. Otherwise, - the cursor's own horizontal position is used. The returned - cursor will have its goal column set to whichever column was - used. - */ - moveVertically(start, forward, distance) { - return skipAtoms(this, start, moveVertically(this, start, forward, distance)); + /// Get a goto table entry @internal + getGoto(state, term, loose = false) { + let table = this.goto; + if (term >= table[0]) + return -1; + for (let pos = table[term + 1];;) { + let groupTag = table[pos++], last = groupTag & 1; + let target = table[pos++]; + if (last && loose) + return target; + for (let end = pos + (groupTag >> 1); pos < end; pos++) + if (table[pos] == state) + return target; + if (last) + return -1; + } } - // FIXME remove on next major version - scrollPosIntoView(pos) { - this.dispatch({ effects: scrollTo.of(state.EditorSelection.cursor(pos)) }); + /// Check if this state has an action for a given terminal @internal + hasAction(state, terminal) { + let data = this.data; + for (let set = 0; set < 2; set++) { + for (let i = this.stateSlot(state, set ? 2 /* Skip */ : 1 /* Actions */), next;; i += 3) { + if ((next = data[i]) == 65535 /* End */) { + if (data[i + 1] == 1 /* Next */) + next = data[i = pair(data, i + 2)]; + else if (data[i + 1] == 2 /* Other */) + return pair(data, i + 2); + else + break; + } + if (next == terminal || next == 0 /* Err */) + return pair(data, i + 1); + } + } + return 0; } - /** - Find the DOM parent node and offset (child offset if `node` is - an element, character offset when it is a text node) at the - given document position. - - Note that for positions that aren't currently in - `visibleRanges`, the resulting DOM position isn't necessarily - meaningful (it may just point before or after a placeholder - element). - */ - domAtPos(pos) { - return this.docView.domAtPos(pos); + /// @internal + stateSlot(state, slot) { + return this.states[(state * 6 /* Size */) + slot]; } - /** - Find the document position at the given DOM node. Can be useful - for associating positions with DOM events. Will raise an error - when `node` isn't part of the editor content. - */ - posAtDOM(node, offset = 0) { - return this.docView.posFromDOM(node, offset); + /// @internal + stateFlag(state, flag) { + return (this.stateSlot(state, 0 /* Flags */) & flag) > 0; } - posAtCoords(coords, precise = true) { - this.readMeasured(); - return posAtCoords(this, coords, precise); + /// @internal + validAction(state, action) { + if (action == this.stateSlot(state, 4 /* DefaultReduce */)) + return true; + for (let i = this.stateSlot(state, 1 /* Actions */);; i += 3) { + if (this.data[i] == 65535 /* End */) { + if (this.data[i + 1] == 1 /* Next */) + i = pair(this.data, i + 2); + else + return false; + } + if (action == pair(this.data, i + 1)) + return true; + } } - /** - Get the screen coordinates at the given document position. - `side` determines whether the coordinates are based on the - element before (-1) or after (1) the position (if no element is - available on the given side, the method will transparently use - another strategy to get reasonable coordinates). - */ - coordsAtPos(pos, side = 1) { - this.readMeasured(); - let rect = this.docView.coordsAt(pos, side); - if (!rect || rect.left == rect.right) - return rect; - let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line); - let span = order[BidiSpan.find(order, pos - line.from, -1, side)]; - return flattenRect(rect, (span.dir == exports.Direction.LTR) == (side > 0)); + /// Get the states that can follow this one through shift actions or + /// goto jumps. @internal + nextStates(state) { + let result = []; + for (let i = this.stateSlot(state, 1 /* Actions */);; i += 3) { + if (this.data[i] == 65535 /* End */) { + if (this.data[i + 1] == 1 /* Next */) + i = pair(this.data, i + 2); + else + break; + } + if ((this.data[i + 2] & (65536 /* ReduceFlag */ >> 16)) == 0) { + let value = this.data[i + 1]; + if (!result.some((v, i) => (i & 1) && v == value)) + result.push(this.data[i], value); + } + } + return result; } - /** - The default width of a character in the editor. May not - accurately reflect the width of all characters (given variable - width fonts or styling of invididual ranges). - */ - get defaultCharacterWidth() { return this.viewState.heightOracle.charWidth; } - /** - The default height of a line in the editor. May not be accurate - for all lines. - */ - get defaultLineHeight() { return this.viewState.heightOracle.lineHeight; } - /** - The text direction - ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction) - CSS property) of the editor. - */ - get textDirection() { return this.viewState.heightOracle.direction; } - /** - Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping) - (as determined by the - [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space) - CSS property of its content element). - */ - get lineWrapping() { return this.viewState.heightOracle.lineWrapping; } - /** - Returns the bidirectional text structure of the given line - (which should be in the current document) as an array of span - objects. The order of these spans matches the [text - direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection)—if that is - left-to-right, the leftmost spans come first, otherwise the - rightmost spans come first. - */ - bidiSpans(line) { - if (line.length > MaxBidiLine) - return trivialOrder(line.length); - let dir = this.textDirection; - for (let entry of this.bidiCache) - if (entry.from == line.from && entry.dir == dir) - return entry.order; - let order = computeOrder(line.text, this.textDirection); - this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order)); - return order; + /// @internal + overrides(token, prev) { + let iPrev = findOffset(this.data, this.tokenPrecTable, prev); + return iPrev < 0 || findOffset(this.data, this.tokenPrecTable, token) < iPrev; } - /** - Check whether the editor has focus. - */ - get hasFocus() { - var _a; - // Safari return false for hasFocus when the context menu is open - // or closing, which leads us to ignore selection changes from the - // context menu because it looks like the editor isn't focused. - // This kludges around that. - return (document.hasFocus() || browser.safari && ((_a = this.inputState) === null || _a === void 0 ? void 0 : _a.lastContextMenu) > Date.now() - 3e4) && - this.root.activeElement == this.contentDOM; + /// Configure the parser. Returns a new parser instance that has the + /// given settings modified. Settings not provided in `config` are + /// kept from the original parser. + configure(config) { + // Hideous reflection-based kludge to make it easy to create a + // slightly modified copy of a parser. + let copy = Object.assign(Object.create(LRParser.prototype), this); + if (config.props) + copy.nodeSet = this.nodeSet.extend(...config.props); + if (config.top) { + let info = this.topRules[config.top]; + if (!info) + throw new RangeError(`Invalid top rule name ${config.top}`); + copy.top = info; + } + if (config.tokenizers) + copy.tokenizers = this.tokenizers.map(t => { + let found = config.tokenizers.find(r => r.from == t); + return found ? found.to : t; + }); + if (config.contextTracker) + copy.context = config.contextTracker; + if (config.dialect) + copy.dialect = this.parseDialect(config.dialect); + if (config.strict != null) + copy.strict = config.strict; + if (config.wrap) + copy.wrappers = copy.wrappers.concat(config.wrap); + if (config.bufferLength != null) + copy.bufferLength = config.bufferLength; + return copy; } - /** - Put focus on the editor. - */ - focus() { - this.observer.ignore(() => { - focusPreventScroll(this.contentDOM); - this.docView.updateSelection(); - }); + /// Returns the name associated with a given term. This will only + /// work for all terms when the parser was generated with the + /// `--names` option. By default, only the names of tagged terms are + /// stored. + getName(term) { + return this.termNames ? this.termNames[term] : String(term <= this.maxNode && this.nodeSet.types[term].name || term); } - /** - Clean up this editor view, removing its element from the - document, unregistering event handlers, and notifying - plugins. The view instance can no longer be used after - calling this. - */ - destroy() { - for (let plugin of this.plugins) - plugin.destroy(this); - this.plugins = []; - this.inputState.destroy(); - this.dom.remove(); - this.observer.destroy(); - if (this.measureScheduled > -1) - cancelAnimationFrame(this.measureScheduled); - this.destroyed = true; + /// The eof term id is always allocated directly after the node + /// types. @internal + get eofTerm() { return this.maxNode + 1; } + /// The type of top node produced by the parser. + get topNode() { return this.nodeSet.types[this.top[1]]; } + /// @internal + dynamicPrecedence(term) { + let prec = this.dynamicPrecedences; + return prec == null ? 0 : prec[term] || 0; } - /** - Returns an effect that can be - [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to - cause it to scroll the given position or range into view. - */ - static scrollIntoView(pos, options = {}) { - return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? state.EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin)); + /// @internal + parseDialect(dialect) { + let values = Object.keys(this.dialects), flags = values.map(() => false); + if (dialect) + for (let part of dialect.split(" ")) { + let id = values.indexOf(part); + if (id >= 0) + flags[id] = true; + } + let disabled = null; + for (let i = 0; i < values.length; i++) + if (!flags[i]) { + for (let j = this.dialects[values[i]], id; (id = this.data[j++]) != 65535 /* End */;) + (disabled || (disabled = new Uint8Array(this.maxTerm + 1)))[id] = 1; + } + return new Dialect(dialect, flags, disabled); } - /** - Facet that can be used to add DOM event handlers. The value - should be an object mapping event names to handler functions. The - first such function to return true will be assumed to have handled - that event, and no other handlers or built-in behavior will be - activated for it. - These are registered on the [content - element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except for `scroll` - handlers, which will be called any time the editor's [scroll - element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of its parent nodes - is scrolled. - */ - static domEventHandlers(handlers) { - return ViewPlugin.define(() => ({}), { eventHandlers: handlers }); + /// (used by the output of the parser generator) @internal + static deserialize(spec) { + return new LRParser(spec); } - /** - Create a theme extension. The first argument can be a - [`style-mod`](https://github.com/marijnh/style-mod#documentation) - style spec providing the styles for the theme. These will be - prefixed with a generated class for the style. - - Because the selectors will be prefixed with a scope class, rule - that directly match the editor's [wrapper - element](https://codemirror.net/6/docs/ref/#view.EditorView.dom)—to which the scope class will be - added—need to be explicitly differentiated by adding an `&` to - the selector for that element—for example - `&.cm-focused`. - - When `dark` is set to true, the theme will be marked as dark, - which will cause the `&dark` rules from [base - themes](https://codemirror.net/6/docs/ref/#view.EditorView^baseTheme) to be used (as opposed to - `&light` when a light theme is active). - */ - static theme(spec, options) { - let prefix = styleMod.StyleModule.newName(); - let result = [theme.of(prefix), styleModule.of(buildTheme(`.${prefix}`, spec))]; - if (options && options.dark) - result.push(darkTheme.of(true)); - return result; +} +function pair(data, off) { return data[off] | (data[off + 1] << 16); } +function findOffset(data, start, term) { + for (let i = start, next; (next = data[i]) != 65535 /* End */; i++) + if (next == term) + return i - start; + return -1; +} +function findFinished(stacks) { + let best = null; + for (let stack of stacks) { + let stopped = stack.p.stoppedAt; + if ((stack.pos == stack.p.stream.end || stopped != null && stack.pos > stopped) && + stack.p.parser.stateFlag(stack.state, 2 /* Accepting */) && + (!best || best.score < stack.score)) + best = stack; } - /** - Create an extension that adds styles to the base theme. Like - with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the - place of the editor wrapper element when directly targeting - that. You can also use `&dark` or `&light` instead to only - target editors with a dark or light theme. - */ - static baseTheme(spec) { - return state.Prec.lowest(styleModule.of(buildTheme("." + baseThemeID, spec, lightDarkIDs))); + return best; +} + +exports.ContextTracker = ContextTracker; +exports.ExternalTokenizer = ExternalTokenizer; +exports.InputStream = InputStream; +exports.LRParser = LRParser; +exports.Stack = Stack; + +}).call(this)}).call(this,require('_process')) +},{"@lezer/common":34,"_process":121}],37:[function(require,module,exports){ +(function (global){(function (){ +'use strict'; + +var objectAssign = require('object-assign'); + +// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js +// original notice: + +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +function compare(a, b) { + if (a === b) { + return 0; + } + + var x = a.length; + var y = b.length; + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; } + } + + if (x < y) { + return -1; + } + if (y < x) { + return 1; + } + return 0; +} +function isBuffer(b) { + if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { + return global.Buffer.isBuffer(b); + } + return !!(b != null && b._isBuffer); } -/** -Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a -transaction to make it scroll the given range into view. -*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead. -*/ -EditorView.scrollTo = scrollTo; -/** -Effect that makes the editor scroll the given range to the -center of the visible view. +// based on node assert, original notice: +// NB: The URL to the CommonJS spec is kept just for tradition. +// node-assert has evolved a lot since then, both in API and behavior. -*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead. -*/ -EditorView.centerOn = centerOn; -/** -Facet to add a [style -module](https://github.com/marijnh/style-mod#documentation) to -an editor view. The view will ensure that the module is -mounted in its [document -root](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.root). -*/ -EditorView.styleModule = styleModule; -/** -An input handler can override the way changes to the editable -DOM content are handled. Handlers are passed the document -positions between which the change was found, and the new -content. When one returns true, no further input handlers are -called and the default behavior is prevented. -*/ -EditorView.inputHandler = inputHandler; -/** -Allows you to provide a function that should be called when the -library catches an exception from an extension (mostly from view -plugins, but may be used by other extensions to route exceptions -from user-code-provided callbacks). This is mostly useful for -debugging and logging. See [`logException`](https://codemirror.net/6/docs/ref/#view.logException). -*/ -EditorView.exceptionSink = exceptionSink; -/** -A facet that can be used to register a function to be called -every time the view updates. -*/ -EditorView.updateListener = updateListener; -/** -Facet that controls whether the editor content DOM is editable. -When its highest-precedence value is `false`, the element will -not longer have its `contenteditable` attribute set. (Note that -this doesn't affect API calls that change the editor content, -even when those are bound to keys or buttons. See the -[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.) -*/ -EditorView.editable = editable; -/** -Allows you to influence the way mouse selection happens. The -functions in this facet will be called for a `mousedown` event -on the editor, and can return an object that overrides the way a -selection is computed from that mouse click or drag. -*/ -EditorView.mouseSelectionStyle = mouseSelectionStyle; -/** -Facet used to configure whether a given selection drag event -should move or copy the selection. The given predicate will be -called with the `mousedown` event, and can return `true` when -the drag should move the content. -*/ -EditorView.dragMovesSelection = dragMovesSelection$1; -/** -Facet used to configure whether a given selecting click adds -a new range to the existing selection or replaces it entirely. -*/ -EditorView.clickAddsSelectionRange = clickAddsSelectionRange; -/** -A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration) -are shown in the view. See also [view -plugins](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), which have a separate -mechanism for providing decorations. -*/ -EditorView.decorations = decorations; -/** -This facet records whether a dark theme is active. The extension -returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically -includes an instance of this when the `dark` option is set to -true. -*/ -EditorView.darkTheme = darkTheme; -/** -Facet that provides additional DOM attributes for the editor's -editable DOM element. -*/ -EditorView.contentAttributes = contentAttributes; -/** -Facet that provides DOM attributes for the editor's outer -element. -*/ -EditorView.editorAttributes = editorAttributes; -/** -An extension that enables line wrapping in the editor (by -setting CSS `white-space` to `pre-wrap` in the content). -*/ -EditorView.lineWrapping = EditorView.contentAttributes.of({ "class": "cm-lineWrapping" }); -/** -State effect used to include screen reader announcements in a -transaction. These will be added to the DOM in a visually hidden -element with `aria-live="polite"` set, and should be used to -describe effects that are visually obvious but may not be -noticed by screen reader users (such as moving to the next -search match). -*/ -EditorView.announce = state.StateEffect.define(); -// Maximum line length for which we compute accurate bidi info -const MaxBidiLine = 4096; -// FIXME remove this and its callers on next breaking release -function ensureTop(given, view) { - return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop; +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +var util = require('util/'); +var hasOwn = Object.prototype.hasOwnProperty; +var pSlice = Array.prototype.slice; +var functionsHaveNames = (function () { + return function foo() {}.name === 'foo'; +}()); +function pToString (obj) { + return Object.prototype.toString.call(obj); +} +function isView(arrbuf) { + if (isBuffer(arrbuf)) { + return false; + } + if (typeof global.ArrayBuffer !== 'function') { + return false; + } + if (typeof ArrayBuffer.isView === 'function') { + return ArrayBuffer.isView(arrbuf); + } + if (!arrbuf) { + return false; + } + if (arrbuf instanceof DataView) { + return true; + } + if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { + return true; + } + return false; +} +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +var regex = /\s*function\s+([^\(\s]*)\s*/; +// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js +function getName(func) { + if (!util.isFunction(func)) { + return; + } + if (functionsHaveNames) { + return func.name; + } + var str = func.toString(); + var match = str.match(regex); + return match && match[1]; +} +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = getName(stackStartFunction); + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function truncate(s, n) { + if (typeof s === 'string') { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } } -let resizeDebounce = -1; -function ensureGlobalHandler() { - window.addEventListener("resize", () => { - if (resizeDebounce == -1) - resizeDebounce = setTimeout(handleResize, 50); - }); +function inspect(something) { + if (functionsHaveNames || !util.isFunction(something)) { + return util.inspect(something); + } + var rawname = getName(something); + var name = rawname ? ': ' + rawname : ''; + return '[Function' + name + ']'; } -function handleResize() { - resizeDebounce = -1; - let found = document.querySelectorAll(".cm-content"); - for (let i = 0; i < found.length; i++) { - let docView = ContentView.get(found[i]); - if (docView) - docView.editorView.requestMeasure(); - } +function getMessage(self) { + return truncate(inspect(self.actual), 128) + ' ' + + self.operator + ' ' + + truncate(inspect(self.expected), 128); } -const BadMeasure = {}; -class CachedOrder { - constructor(from, to, dir, order) { - this.from = from; - this.to = to; - this.dir = dir; - this.order = order; - } - static update(cache, changes) { - if (changes.empty) - return cache; - let result = [], lastDir = cache.length ? cache[cache.length - 1].dir : exports.Direction.LTR; - for (let i = Math.max(0, cache.length - 10); i < cache.length; i++) { - let entry = cache[i]; - if (entry.dir == lastDir && !changes.touchesRange(entry.from, entry.to)) - result.push(new CachedOrder(changes.mapPos(entry.from, 1), changes.mapPos(entry.to, -1), entry.dir, entry.order)); - } - return result; - } + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); } -function attrsFromFacet(view, facet, base) { - for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) { - let source = sources[i], value = typeof source == "function" ? source(view) : source; - if (value) - combineAttrs(value, base); - } - return base; + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); } +assert.ok = ok; -const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key"; -function normalizeKeyName(name, platform) { - const parts = name.split(/-(?!$)/); - let result = parts[parts.length - 1]; - if (result == "Space") - result = " "; - let alt, ctrl, shift, meta; - for (let i = 0; i < parts.length - 1; ++i) { - const mod = parts[i]; - if (/^(cmd|meta|m)$/i.test(mod)) - meta = true; - else if (/^a(lt)?$/i.test(mod)) - alt = true; - else if (/^(c|ctrl|control)$/i.test(mod)) - ctrl = true; - else if (/^s(hift)?$/i.test(mod)) - shift = true; - else if (/^mod$/i.test(mod)) { - if (platform == "mac") - meta = true; - else - ctrl = true; - } - else - throw new Error("Unrecognized modifier name: " + mod); +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); + } +}; + +function _deepEqual(actual, expected, strict, memos) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + } else if (isBuffer(actual) && isBuffer(expected)) { + return compare(actual, expected) === 0; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if ((actual === null || typeof actual !== 'object') && + (expected === null || typeof expected !== 'object')) { + return strict ? actual === expected : actual == expected; + + // If both values are instances of typed arrays, wrap their underlying + // ArrayBuffers in a Buffer each to increase performance + // This optimization requires the arrays to have the same type as checked by + // Object.prototype.toString (aka pToString). Never perform binary + // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their + // bit patterns are not identical. + } else if (isView(actual) && isView(expected) && + pToString(actual) === pToString(expected) && + !(actual instanceof Float32Array || + actual instanceof Float64Array)) { + return compare(new Uint8Array(actual.buffer), + new Uint8Array(expected.buffer)) === 0; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else if (isBuffer(actual) !== isBuffer(expected)) { + return false; + } else { + memos = memos || {actual: [], expected: []}; + + var actualIndex = memos.actual.indexOf(actual); + if (actualIndex !== -1) { + if (actualIndex === memos.expected.indexOf(expected)) { + return true; + } } - if (alt) - result = "Alt-" + result; - if (ctrl) - result = "Ctrl-" + result; - if (meta) - result = "Meta-" + result; - if (shift) - result = "Shift-" + result; - return result; + + memos.actual.push(actual); + memos.expected.push(expected); + + return objEquiv(actual, expected, strict, memos); + } } -function modifiers(name, event, shift) { - if (event.altKey) - name = "Alt-" + name; - if (event.ctrlKey) - name = "Ctrl-" + name; - if (event.metaKey) - name = "Meta-" + name; - if (shift !== false && event.shiftKey) - name = "Shift-" + name; - return name; + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; } -const handleKeyEvents = EditorView.domEventHandlers({ - keydown(event, view) { - return runHandlers(getKeymap(view.state), event, view, "editor"); - } -}); -/** -Facet used for registering keymaps. -You can add multiple keymaps to an editor. Their priorities -determine their precedence (the ones specified early or with high -priority get checked first). When a handler has returned `true` -for a given key, no further handlers are called. -*/ -const keymap = state.Facet.define({ enables: handleKeyEvents }); -const Keymaps = new WeakMap(); -// This is hidden behind an indirection, rather than directly computed -// by the facet, to keep internal types out of the facet's type. -function getKeymap(state) { - let bindings = state.facet(keymap); - let map = Keymaps.get(bindings); - if (!map) - Keymaps.set(bindings, map = buildKeymap(bindings.reduce((a, b) => a.concat(b), []))); - return map; +function objEquiv(a, b, strict, actualVisitedObjects) { + if (a === null || a === undefined || b === null || b === undefined) + return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) + return a === b; + if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) + return false; + var aIsArgs = isArguments(a); + var bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b, strict); + } + var ka = objectKeys(a); + var kb = objectKeys(b); + var key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length !== kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] !== kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) + return false; + } + return true; } -/** -Run the key handlers registered for a given scope. The event -object should be `"keydown"` event. Returns true if any of the -handlers handled it. -*/ -function runScopeHandlers(view, event, scope) { - return runHandlers(getKeymap(view.state), event, view, scope); + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +assert.notDeepStrictEqual = notDeepStrictEqual; +function notDeepStrictEqual(actual, expected, message) { + if (_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); + } } -let storedPrefix = null; -const PrefixTimeout = 4000; -function buildKeymap(bindings, platform = currentPlatform) { - let bound = Object.create(null); - let isPrefix = Object.create(null); - let checkPrefix = (name, is) => { - let current = isPrefix[name]; - if (current == null) - isPrefix[name] = is; - else if (current != is) - throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix"); - }; - let add = (scope, key, command, preventDefault) => { - let scopeObj = bound[scope] || (bound[scope] = Object.create(null)); - let parts = key.split(/ (?!$)/).map(k => normalizeKeyName(k, platform)); - for (let i = 1; i < parts.length; i++) { - let prefix = parts.slice(0, i).join(" "); - checkPrefix(prefix, true); - if (!scopeObj[prefix]) - scopeObj[prefix] = { - preventDefault: true, - commands: [(view) => { - let ourObj = storedPrefix = { view, prefix, scope }; - setTimeout(() => { if (storedPrefix == ourObj) - storedPrefix = null; }, PrefixTimeout); - return true; - }] - }; - } - let full = parts.join(" "); - checkPrefix(full, false); - let binding = scopeObj[full] || (scopeObj[full] = { preventDefault: false, commands: [] }); - binding.commands.push(command); - if (preventDefault) - binding.preventDefault = true; - }; - for (let b of bindings) { - let name = b[platform] || b.key; - if (!name) - continue; - for (let scope of b.scope ? b.scope.split(" ") : ["editor"]) { - add(scope, name, b.run, b.preventDefault); - if (b.shift) - add(scope, "Shift-" + name, b.shift, b.preventDefault); - } + + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } + + try { + if (actual instanceof expected) { + return true; } - return bound; + } catch (e) { + // Ignore. The instanceof check doesn't work for arrow functions. + } + + if (Error.isPrototypeOf(expected)) { + return false; + } + + return expected.call({}, actual) === true; } -function runHandlers(map, event, view, scope) { - let name = w3cKeyname.keyName(event), isChar = name.length == 1 && name != " "; - let prefix = "", fallthrough = false; - if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) { - prefix = storedPrefix.prefix + " "; - if (fallthrough = modifierCodes.indexOf(event.keyCode) < 0) - storedPrefix = null; - } - let runFor = (binding) => { - if (binding) { - for (let cmd of binding.commands) - if (cmd(view)) - return true; - if (binding.preventDefault) - fallthrough = true; - } - return false; - }; - let scopeObj = map[scope], baseName; - if (scopeObj) { - if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)])) - return true; - if (isChar && (event.shiftKey || event.altKey || event.metaKey) && - (baseName = w3cKeyname.base[event.keyCode]) && baseName != name) { - if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) - return true; - } - else if (isChar && event.shiftKey) { - if (runFor(scopeObj[prefix + modifiers(name, event, true)])) - return true; - } - } - return fallthrough; + +function _tryBlock(block) { + var error; + try { + block(); + } catch (e) { + error = e; + } + return error; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (typeof block !== 'function') { + throw new TypeError('"block" argument must be a function'); + } + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + actual = _tryBlock(block); + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + var userProvidedMessage = typeof message === 'string'; + var isUnwantedException = !shouldThrow && util.isError(actual); + var isUnexpectedException = !shouldThrow && actual && !expected; + + if ((isUnwantedException && + userProvidedMessage && + expectedException(actual, expected)) || + isUnexpectedException) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } } -const CanHidePrimary = !browser.ios; // FIXME test IE -const selectionConfig = state.Facet.define({ - combine(configs) { - return state.combineConfig(configs, { - cursorBlinkRate: 1200, - drawRangeCursor: true - }, { - cursorBlinkRate: (a, b) => Math.min(a, b), - drawRangeCursor: (a, b) => a || b - }); - } +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws(true, block, error, message); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws(false, block, error, message); +}; + +assert.ifError = function(err) { if (err) throw err; }; + +// Expose a strict only variant of assert +function strict(value, message) { + if (!value) fail(value, true, message, '==', strict); +} +assert.strict = objectAssign(strict, assert, { + equal: assert.strictEqual, + deepEqual: assert.deepStrictEqual, + notEqual: assert.notStrictEqual, + notDeepEqual: assert.notDeepStrictEqual }); -/** -Returns an extension that hides the browser's native selection and -cursor, replacing the selection with a background behind the text -(with the `cm-selectionBackground` class), and the -cursors with elements overlaid over the code (using -`cm-cursor-primary` and `cm-cursor-secondary`). +assert.strict.strict = assert.strict; -This allows the editor to display secondary selection ranges, and -tends to produce a type of selection more in line with that users -expect in a text editor (the native selection styling will often -leave gaps between lines and won't fill the horizontal space after -a line when the selection continues past it). +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; -It does have a performance cost, in that it requires an extra DOM -layout cycle for many updates (the selection is drawn based on DOM -layout information that's only available after laying out the -content). -*/ -function drawSelection(config = {}) { - return [ - selectionConfig.of(config), - drawSelectionPlugin, - hideNativeSelection - ]; +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"object-assign":114,"util/":40}],38:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } } -class Piece { - constructor(left, top, width, height, className) { - this.left = left; - this.top = top; - this.width = width; - this.height = height; - this.className = className; - } - draw() { - let elt = document.createElement("div"); - elt.className = this.className; - this.adjust(elt); - return elt; - } - adjust(elt) { - elt.style.left = this.left + "px"; - elt.style.top = this.top + "px"; - if (this.width >= 0) - elt.style.width = this.width + "px"; - elt.style.height = this.height + "px"; - } - eq(p) { - return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height && - this.className == p.className; - } + +},{}],39:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; } -const drawSelectionPlugin = ViewPlugin.fromClass(class { - constructor(view) { - this.view = view; - this.rangePieces = []; - this.cursors = []; - this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) }; - this.selectionLayer = view.scrollDOM.appendChild(document.createElement("div")); - this.selectionLayer.className = "cm-selectionLayer"; - this.selectionLayer.setAttribute("aria-hidden", "true"); - this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div")); - this.cursorLayer.className = "cm-cursorLayer"; - this.cursorLayer.setAttribute("aria-hidden", "true"); - view.requestMeasure(this.measureReq); - this.setBlinkRate(); - } - setBlinkRate() { - this.cursorLayer.style.animationDuration = this.view.state.facet(selectionConfig).cursorBlinkRate + "ms"; - } - update(update) { - let confChanged = update.startState.facet(selectionConfig) != update.state.facet(selectionConfig); - if (confChanged || update.selectionSet || update.geometryChanged || update.viewportChanged) - this.view.requestMeasure(this.measureReq); - if (update.transactions.some(tr => tr.scrollIntoView)) - this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink"; - if (confChanged) - this.setBlinkRate(); +},{}],40:[function(require,module,exports){ +(function (process,global){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); } - readPos() { - let { state } = this.view, conf = state.facet(selectionConfig); - let rangePieces = state.selection.ranges.map(r => r.empty ? [] : measureRange(this.view, r)).reduce((a, b) => a.concat(b)); - let cursors = []; - for (let r of state.selection.ranges) { - let prim = r == state.selection.main; - if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) { - let piece = measureCursor(this.view, r, prim); - if (piece) - cursors.push(piece); - } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; } - return { rangePieces, cursors }; + default: + return x; } - drawSel({ rangePieces, cursors }) { - if (rangePieces.length != this.rangePieces.length || rangePieces.some((p, i) => !p.eq(this.rangePieces[i]))) { - this.selectionLayer.textContent = ""; - for (let p of rangePieces) - this.selectionLayer.appendChild(p.draw()); - this.rangePieces = rangePieces; - } - if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) { - let oldCursors = this.cursorLayer.children; - if (oldCursors.length !== cursors.length) { - this.cursorLayer.textContent = ""; - for (const c of cursors) - this.cursorLayer.appendChild(c.draw()); - } - else { - cursors.forEach((c, idx) => c.adjust(oldCursors[idx])); - } - this.cursors = cursors; - } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); } - destroy() { - this.selectionLayer.remove(); - this.cursorLayer.remove(); + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; } -}); -const themeSpec = { - ".cm-line": { - "& ::selection": { backgroundColor: "transparent !important" }, - "&::selection": { backgroundColor: "transparent !important" } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; } + } + return debugs[set]; }; -if (CanHidePrimary) - themeSpec[".cm-line"].caretColor = "transparent !important"; -const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec)); -function getBase(view) { - let rect = view.scrollDOM.getBoundingClientRect(); - let left = view.textDirection == exports.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth; - return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop }; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); } -function wrappedLine(view, pos, inside) { - let range = state.EditorSelection.cursor(pos); - return { from: Math.max(inside.from, view.moveToLineBoundary(range, false, true).from), - to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from), - type: exports.BlockType.Text }; +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } } -function blockAt(view, pos) { - let line = view.lineBlockAt(pos); - if (Array.isArray(line.type)) - for (let l of line.type) { - if (l.to > pos || l.to == pos && (l.to == line.to || l.type == exports.BlockType.Text)) - return l; - } - return line; + + +function stylizeNoColor(str, styleType) { + return str; } -function measureRange(view, range) { - if (range.to <= view.viewport.from || range.from >= view.viewport.to) - return []; - let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to); - let ltr = view.textDirection == exports.Direction.LTR; - let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view); - let lineStyle = window.getComputedStyle(content.firstChild); - let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent)); - let rightSide = contentRect.right - parseInt(lineStyle.paddingRight); - let startBlock = blockAt(view, from), endBlock = blockAt(view, to); - let visualStart = startBlock.type == exports.BlockType.Text ? startBlock : null; - let visualEnd = endBlock.type == exports.BlockType.Text ? endBlock : null; - if (view.lineWrapping) { - if (visualStart) - visualStart = wrappedLine(view, from, visualStart); - if (visualEnd) - visualEnd = wrappedLine(view, to, visualEnd); - } - if (visualStart && visualEnd && visualStart.from == visualEnd.from) { - return pieces(drawForLine(range.from, range.to, visualStart)); - } - else { - let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false); - let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true); - let between = []; - if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1) - between.push(piece(leftSide, top.bottom, rightSide, bottom.top)); - else if (top.bottom < bottom.top && view.elementAtHeight((top.bottom + bottom.top) / 2).type == exports.BlockType.Text) - top.bottom = bottom.top = (top.bottom + bottom.top) / 2; - return pieces(top).concat(between).concat(pieces(bottom)); - } - function piece(left, top, right, bottom) { - return new Piece(left - base.left, top - base.top - 0.01 /* Epsilon */, right - left, bottom - top + 0.01 /* Epsilon */, "cm-selectionBackground"); + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); } - function pieces({ top, bottom, horizontal }) { - let pieces = []; - for (let i = 0; i < horizontal.length; i += 2) - pieces.push(piece(horizontal[i], top, horizontal[i + 1], bottom)); - return pieces; + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); } - // Gets passed from/to in line-local positions - function drawForLine(from, to, line) { - let top = 1e9, bottom = -1e9, horizontal = []; - function addSpan(from, fromOpen, to, toOpen, dir) { - // Passing 2/-2 is a kludge to force the view to return - // coordinates on the proper side of block widgets, since - // normalizing the side there, though appropriate for most - // coordsAtPos queries, would break selection drawing. - let fromCoords = view.coordsAtPos(from, (from == line.to ? -2 : 2)); - let toCoords = view.coordsAtPos(to, (to == line.from ? 2 : -2)); - top = Math.min(fromCoords.top, toCoords.top, top); - bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom); - if (dir == exports.Direction.LTR) - horizontal.push(ltr && fromOpen ? leftSide : fromCoords.left, ltr && toOpen ? rightSide : toCoords.right); - else - horizontal.push(!ltr && toOpen ? leftSide : toCoords.left, !ltr && fromOpen ? rightSide : fromCoords.right); - } - let start = from !== null && from !== void 0 ? from : line.from, end = to !== null && to !== void 0 ? to : line.to; - // Split the range by visible range and document line - for (let r of view.visibleRanges) - if (r.to > start && r.from < end) { - for (let pos = Math.max(r.from, start), endPos = Math.min(r.to, end);;) { - let docLine = view.state.doc.lineAt(pos); - for (let span of view.bidiSpans(docLine)) { - let spanFrom = span.from + docLine.from, spanTo = span.to + docLine.from; - if (spanFrom >= endPos) - break; - if (spanTo > pos) - addSpan(Math.max(spanFrom, pos), from == null && spanFrom <= start, Math.min(spanTo, endPos), to == null && spanTo >= end, span.dir); - } - pos = docLine.to + 1; - if (pos >= endPos) - break; - } - } - if (horizontal.length == 0) - addSpan(start, from == null, end, to == null, view.textDirection); - return { top, bottom, horizontal }; + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } - function drawForWidget(block, top) { - let y = contentRect.top + (top ? block.top : block.bottom); - return { top: y, bottom: y, horizontal: [] }; + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); } -function measureCursor(view, cursor, primary) { - let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1); - if (!pos) - return null; - let base = getBase(view); - return new Piece(pos.left - base.left, pos.top - base.top, -1, pos.bottom - pos.top, primary ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary"); + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); } -const setDropCursorPos = state.StateEffect.define({ - map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); } -}); -const dropCursorPos = state.StateField.define({ - create() { return null; }, - update(pos, tr) { - if (pos != null) - pos = tr.changes.mapPos(pos); - return tr.effects.reduce((pos, e) => e.is(setDropCursorPos) ? e.value : pos, pos); + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); } -}); -const drawDropCursor = ViewPlugin.fromClass(class { - constructor(view) { - this.view = view; - this.cursor = null; - this.measureReq = { read: this.readPos.bind(this), write: this.drawCursor.bind(this) }; + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); } - update(update) { - var _a; - let cursorPos = update.state.field(dropCursorPos); - if (cursorPos == null) { - if (this.cursor != null) { - (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.remove(); - this.cursor = null; - } - } - else { - if (!this.cursor) { - this.cursor = this.view.scrollDOM.appendChild(document.createElement("div")); - this.cursor.className = "cm-dropCursor"; - } - if (update.startState.field(dropCursorPos) != cursorPos || update.docChanged || update.geometryChanged) - this.view.requestMeasure(this.measureReq); - } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); } - readPos() { - let pos = this.view.state.field(dropCursorPos); - let rect = pos != null && this.view.coordsAtPos(pos); - if (!rect) - return null; - let outer = this.view.scrollDOM.getBoundingClientRect(); - return { - left: rect.left - outer.left + this.view.scrollDOM.scrollLeft, - top: rect.top - outer.top + this.view.scrollDOM.scrollTop, - height: rect.bottom - rect.top - }; + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); } - drawCursor(pos) { - if (this.cursor) { - if (pos) { - this.cursor.style.left = pos.left + "px"; - this.cursor.style.top = pos.top + "px"; - this.cursor.style.height = pos.height + "px"; - } - else { - this.cursor.style.left = "-100000px"; - } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); } + } + } else { + str = ctx.stylize('[Circular]', 'special'); } - destroy() { - if (this.cursor) - this.cursor.remove(); - } - setDropPos(pos) { - if (this.view.state.field(dropCursorPos) != pos) - this.view.dispatch({ effects: setDropCursorPos.of(pos) }); + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; } -}, { - eventHandlers: { - dragover(event) { - this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY })); - }, - dragleave(event) { - if (event.target == this.view.contentDOM || !this.view.contentDOM.contains(event.relatedTarget)) - this.setDropPos(null); - }, - dragend() { - this.setDropPos(null); - }, - drop() { - this.setDropPos(null); - } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); } -}); -/** -Draws a cursor at the current drop position when something is -dragged over the editor. -*/ -function dropCursor() { - return [dropCursorPos, drawDropCursor]; + } + + return name + ': ' + str; } -function iterMatches(doc, re, from, to, f) { - re.lastIndex = 0; - for (let cursor = doc.iterRange(from, to), pos = from, m; !cursor.next().done; pos += cursor.value.length) { - if (!cursor.lineBreak) - while (m = re.exec(cursor.value)) - f(pos + m.index, pos + m.index + m[0].length, m); - } + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; } -function matchRanges(view, maxLength) { - let visible = view.visibleRanges; - if (visible.length == 1 && visible[0].from == view.viewport.from && - visible[0].to == view.viewport.to) - return visible; - let result = []; - for (let { from, to } of visible) { - from = Math.max(view.state.doc.lineAt(from).from, from - maxLength); - to = Math.min(view.state.doc.lineAt(to).to, to + maxLength); - if (result.length && result[result.length - 1].to >= from) - result[result.length - 1].to = to; - else - result.push({ from, to }); - } - return result; + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); } -/** -Helper class used to make it easier to maintain decorations on -visible code that matches a given regular expression. To be used -in a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin). Instances of this object -represent a matching configuration. -*/ -class MatchDecorator { - /** - Create a decorator. - */ - constructor(config) { - let { regexp, decoration, boundary, maxLength = 1000 } = config; - if (!regexp.global) - throw new RangeError("The regular expression given to MatchDecorator should have its 'g' flag set"); - this.regexp = regexp; - this.getDeco = typeof decoration == "function" ? decoration : () => decoration; - this.boundary = boundary; - this.maxLength = maxLength; - } - /** - Compute the full set of decorations for matches in the given - view's viewport. You'll want to call this when initializing your - plugin. - */ - createDeco(view) { - let build = new rangeset.RangeSetBuilder(); - for (let { from, to } of matchRanges(view, this.maxLength)) - iterMatches(view.state.doc, this.regexp, from, to, (a, b, m) => build.add(a, b, this.getDeco(m, view, a))); - return build.finish(); - } - /** - Update a set of decorations for a view update. `deco` _must_ be - the set of decorations produced by _this_ `MatchDecorator` for - the view state before the update. - */ - updateDeco(update, deco) { - let changeFrom = 1e9, changeTo = -1; - if (update.docChanged) - update.changes.iterChanges((_f, _t, from, to) => { - if (to > update.view.viewport.from && from < update.view.viewport.to) { - changeFrom = Math.min(from, changeFrom); - changeTo = Math.max(to, changeTo); - } - }); - if (update.viewportChanged || changeTo - changeFrom > 1000) - return this.createDeco(update.view); - if (changeTo > -1) - return this.updateRange(update.view, deco.map(update.changes), changeFrom, changeTo); - return deco; - } - updateRange(view, deco, updateFrom, updateTo) { - for (let r of view.visibleRanges) { - let from = Math.max(r.from, updateFrom), to = Math.min(r.to, updateTo); - if (to > from) { - let fromLine = view.state.doc.lineAt(from), toLine = fromLine.to < to ? view.state.doc.lineAt(to) : fromLine; - let start = Math.max(r.from, fromLine.from), end = Math.min(r.to, toLine.to); - if (this.boundary) { - for (; from > fromLine.from; from--) - if (this.boundary.test(fromLine.text[from - 1 - fromLine.from])) { - start = from; - break; - } - for (; to < toLine.to; to++) - if (this.boundary.test(toLine.text[to - toLine.from])) { - end = to; - break; - } - } - let ranges = [], m; - if (fromLine == toLine) { - this.regexp.lastIndex = start - fromLine.from; - while ((m = this.regexp.exec(fromLine.text)) && m.index < end - fromLine.from) { - let pos = m.index + fromLine.from; - ranges.push(this.getDeco(m, view, pos).range(pos, pos + m[0].length)); - } - } - else { - iterMatches(view.state.doc, this.regexp, start, end, (from, to, m) => ranges.push(this.getDeco(m, view, from).range(from, to))); - } - deco = deco.update({ filterFrom: start, filterTo: end, filter: (from, to) => from < start || to > end, add: ranges }); - } - } - return deco; - } +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; } +exports.isBoolean = isBoolean; -const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g"; -const Specials = new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport); -const Names = { - 0: "null", - 7: "bell", - 8: "backspace", - 10: "newline", - 11: "vertical tab", - 13: "carriage return", - 27: "escape", - 8203: "zero width space", - 8204: "zero width non-joiner", - 8205: "zero width joiner", - 8206: "left-to-right mark", - 8207: "right-to-left mark", - 8232: "line separator", - 8237: "left-to-right override", - 8238: "right-to-left override", - 8233: "paragraph separator", - 65279: "zero width no-break space", - 65532: "object replacement" -}; -let _supportsTabSize = null; -function supportsTabSize() { - var _a; - if (_supportsTabSize == null && typeof document != "undefined" && document.body) { - let styles = document.body.style; - _supportsTabSize = ((_a = styles.tabSize) !== null && _a !== void 0 ? _a : styles.MozTabSize) != null; - } - return _supportsTabSize || false; +function isNull(arg) { + return arg === null; } -const specialCharConfig = state.Facet.define({ - combine(configs) { - let config = state.combineConfig(configs, { - render: null, - specialChars: Specials, - addSpecialChars: null - }); - if (config.replaceTabs = !supportsTabSize()) - config.specialChars = new RegExp("\t|" + config.specialChars.source, UnicodeRegexpSupport); - if (config.addSpecialChars) - config.specialChars = new RegExp(config.specialChars.source + "|" + config.addSpecialChars.source, UnicodeRegexpSupport); - return config; - } -}); -/** -Returns an extension that installs highlighting of special -characters. -*/ -function highlightSpecialChars( -/** -Configuration options. -*/ -config = {}) { - return [specialCharConfig.of(config), specialCharPlugin()]; +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; } -let _plugin = null; -function specialCharPlugin() { - return _plugin || (_plugin = ViewPlugin.fromClass(class { - constructor(view) { - this.view = view; - this.decorations = Decoration.none; - this.decorationCache = Object.create(null); - this.decorator = this.makeDecorator(view.state.facet(specialCharConfig)); - this.decorations = this.decorator.createDeco(view); - } - makeDecorator(conf) { - return new MatchDecorator({ - regexp: conf.specialChars, - decoration: (m, view, pos) => { - let { doc } = view.state; - let code = text.codePointAt(m[0], 0); - if (code == 9) { - let line = doc.lineAt(pos); - let size = view.state.tabSize, col = text.countColumn(line.text, size, pos - line.from); - return Decoration.replace({ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth) }); - } - return this.decorationCache[code] || - (this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) })); - }, - boundary: conf.replaceTabs ? undefined : /[^]/ - }); - } - update(update) { - let conf = update.state.facet(specialCharConfig); - if (update.startState.facet(specialCharConfig) != conf) { - this.decorator = this.makeDecorator(conf); - this.decorations = this.decorator.createDeco(update.view); - } - else { - this.decorations = this.decorator.updateDeco(update, this.decorations); - } - } - }, { - decorations: v => v.decorations - })); +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; } -const DefaultPlaceholder = "\u2022"; -// Assigns placeholder characters from the Control Pictures block to -// ASCII control characters -function placeholder$1(code) { - if (code >= 32) - return DefaultPlaceholder; - if (code == 10) - return "\u2424"; - return String.fromCharCode(9216 + code); +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; } -class SpecialCharWidget extends WidgetType { - constructor(options, code) { - super(); - this.options = options; - this.code = code; - } - eq(other) { return other.code == this.code; } - toDOM(view) { - let ph = placeholder$1(this.code); - let desc = view.state.phrase("Control character") + " " + (Names[this.code] || "0x" + this.code.toString(16)); - let custom = this.options.render && this.options.render(this.code, desc, ph); - if (custom) - return custom; - let span = document.createElement("span"); - span.textContent = ph; - span.title = desc; - span.setAttribute("aria-label", desc); - span.className = "cm-specialChar"; - return span; - } - ignoreEvent() { return false; } +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); } -class TabWidget extends WidgetType { - constructor(width) { - super(); - this.width = width; - } - eq(other) { return other.width == this.width; } - toDOM() { - let span = document.createElement("span"); - span.textContent = "\t"; - span.className = "cm-tab"; - span.style.width = this.width + "px"; - return span; - } - ignoreEvent() { return false; } +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; } +exports.isFunction = isFunction; -const plugin = ViewPlugin.fromClass(class { - constructor() { - this.height = 1000; - this.attrs = { style: "padding-bottom: 1000px" }; - } - update(update) { - let height = update.view.viewState.editorHeight - update.view.defaultLineHeight; - if (height != this.height) { - this.height = height; - this.attrs = { style: `padding-bottom: ${height}px` }; - } - } -}); -/** -Returns an extension that makes sure the content has a bottom -margin equivalent to the height of the editor, minus one line -height, so that every line in the document can be scrolled to the -top of the editor. +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; -This is only meaningful when the editor is scrollable, and should -not be enabled in editors that take the size of their content. -*/ -function scrollPastEnd() { - return [plugin, contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.attrs) || null; })]; +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); } -/** -Mark lines that have a cursor on them with the `"cm-activeLine"` -DOM class. -*/ -function highlightActiveLine() { - return activeLineHighlighter; + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); } -const lineDeco = Decoration.line({ class: "cm-activeLine" }); -const activeLineHighlighter = ViewPlugin.fromClass(class { - constructor(view) { - this.decorations = this.getDeco(view); - } - update(update) { - if (update.docChanged || update.selectionSet) - this.decorations = this.getDeco(update.view); - } - getDeco(view) { - let lastLineStart = -1, deco = []; - for (let r of view.state.selection.ranges) { - if (!r.empty) - return Decoration.none; - let line = view.lineBlockAt(r.head); - if (line.from > lastLineStart) { - deco.push(lineDeco.range(line.from)); - lastLineStart = line.from; - } - } - return Decoration.set(deco); - } -}, { - decorations: v => v.decorations -}); -class Placeholder extends WidgetType { - constructor(content) { - super(); - this.content = content; - } - toDOM() { - let wrap = document.createElement("span"); - wrap.className = "cm-placeholder"; - wrap.style.pointerEvents = "none"; - wrap.appendChild(typeof this.content == "string" ? document.createTextNode(this.content) : this.content); - if (typeof this.content == "string") - wrap.setAttribute("aria-label", "placeholder " + this.content); - else - wrap.setAttribute("aria-hidden", "true"); - return wrap; - } - ignoreEvent() { return false; } + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); } + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + /** -Extension that enables a placeholder—a piece of example content -to show when the editor is empty. -*/ -function placeholder(content) { - return ViewPlugin.fromClass(class { - constructor(view) { - this.view = view; - this.placeholder = Decoration.set([Decoration.widget({ widget: new Placeholder(content), side: 1 }).range(0)]); - } - get decorations() { return this.view.state.doc.length ? Decoration.none : this.placeholder; } - }, { decorations: v => v.decorations }); + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); } -/** -@internal -*/ -const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually }; +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":39,"_process":121,"inherits":38}],41:[function(require,module,exports){ +'use strict' -Object.defineProperty(exports, 'Range', { - enumerable: true, - get: function () { return rangeset.Range; } -}); -exports.BidiSpan = BidiSpan; -exports.BlockInfo = BlockInfo; -exports.Decoration = Decoration; -exports.EditorView = EditorView; -exports.MatchDecorator = MatchDecorator; -exports.PluginField = PluginField; -exports.PluginFieldProvider = PluginFieldProvider; -exports.ViewPlugin = ViewPlugin; -exports.ViewUpdate = ViewUpdate; -exports.WidgetType = WidgetType; -exports.__test = __test; -exports.drawSelection = drawSelection; -exports.dropCursor = dropCursor; -exports.highlightActiveLine = highlightActiveLine; -exports.highlightSpecialChars = highlightSpecialChars; -exports.keymap = keymap; -exports.logException = logException; -exports.placeholder = placeholder; -exports.runScopeHandlers = runScopeHandlers; -exports.scrollPastEnd = scrollPastEnd; +exports.byteLength = byteLength +exports.toByteArray = toByteArray +exports.fromByteArray = fromByteArray -},{"@codemirror/rangeset":50,"@codemirror/state":51,"@codemirror/text":52,"style-mod":120,"w3c-keyname":121}],55:[function(require,module,exports){ -'use strict'; +var lookup = [] +var revLookup = [] +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array -Object.defineProperty(exports, '__esModule', { value: true }); +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i +} -// FIXME profile adding a per-Tree TreeNode cache, validating it by -// parent pointer -/// The default maximum length of a `TreeBuffer` node (1024). -const DefaultBufferLength = 1024; -let nextPropID = 0; -class Range { - constructor(from, to) { - this.from = from; - this.to = to; - } +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 + +function getLens (b64) { + var len = b64.length + + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] } -/// Each [node type](#common.NodeType) or [individual tree](#common.Tree) -/// can have metadata associated with it in props. Instances of this -/// class represent prop names. -class NodeProp { - /// Create a new node prop type. - constructor(config = {}) { - this.id = nextPropID++; - this.perNode = !!config.perNode; - this.deserialize = config.deserialize || (() => { - throw new Error("This node type doesn't define a deserialize function"); - }); - } - /// This is meant to be used with - /// [`NodeSet.extend`](#common.NodeSet.extend) or - /// [`LRParser.configure`](#lr.ParserConfig.props) to compute - /// prop values for each node type in the set. Takes a [match - /// object](#common.NodeType^match) or function that returns undefined - /// if the node type doesn't get this prop, and the prop's value if - /// it does. - add(match) { - if (this.perNode) - throw new RangeError("Can't add per-node props to node types"); - if (typeof match != "function") - match = NodeType.match(match); - return (type) => { - let result = match(type); - return result === undefined ? null : [this, result]; - }; - } + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } -/// Prop that is used to describe matching delimiters. For opening -/// delimiters, this holds an array of node names (written as a -/// space-separated string when declaring this prop in a grammar) -/// for the node types of closing delimiters that match it. -NodeProp.closedBy = new NodeProp({ deserialize: str => str.split(" ") }); -/// The inverse of [`closedBy`](#common.NodeProp^closedBy). This is -/// attached to closing delimiters, holding an array of node names -/// of types of matching opening delimiters. -NodeProp.openedBy = new NodeProp({ deserialize: str => str.split(" ") }); -/// Used to assign node types to groups (for example, all node -/// types that represent an expression could be tagged with an -/// `"Expression"` group). -NodeProp.group = new NodeProp({ deserialize: str => str.split(" ") }); -/// The hash of the [context](#lr.ContextTracker.constructor) -/// that the node was parsed in, if any. Used to limit reuse of -/// contextual nodes. -NodeProp.contextHash = new NodeProp({ perNode: true }); -/// The distance beyond the end of the node that the tokenizer -/// looked ahead for any of the tokens inside the node. (The LR -/// parser only stores this when it is larger than 25, for -/// efficiency reasons.) -NodeProp.lookAhead = new NodeProp({ perNode: true }); -/// This per-node prop is used to replace a given node, or part of a -/// node, with another tree. This is useful to include trees from -/// different languages. -NodeProp.mounted = new NodeProp({ perNode: true }); -/// A mounted tree, which can be [stored](#common.NodeProp^mounted) on -/// a tree node to indicate that parts of its content are -/// represented by another tree. -class MountedTree { - constructor( - /// The inner tree. - tree, - /// If this is null, this tree replaces the entire node (it will - /// be included in the regular iteration instead of its host - /// node). If not, only the given ranges are considered to be - /// covered by this tree. This is used for trees that are mixed in - /// a way that isn't strictly hierarchical. Such mounted trees are - /// only entered by [`resolveInner`](#common.Tree.resolveInner) - /// and [`enter`](#common.SyntaxNode.enter). - overlay, - /// The parser used to create this subtree. - parser) { - this.tree = tree; - this.overlay = overlay; - this.parser = parser; - } + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } -const noProps = Object.create(null); -/// Each node in a syntax tree has a node type associated with it. -class NodeType { - /// @internal - constructor( - /// The name of the node type. Not necessarily unique, but if the - /// grammar was written properly, different node types with the - /// same name within a node set should play the same semantic - /// role. - name, - /// @internal - props, - /// The id of this node in its set. Corresponds to the term ids - /// used in the parser. - id, - /// @internal - flags = 0) { - this.name = name; - this.props = props; - this.id = id; - this.flags = flags; - } - static define(spec) { - let props = spec.props && spec.props.length ? Object.create(null) : noProps; - let flags = (spec.top ? 1 /* Top */ : 0) | (spec.skipped ? 2 /* Skipped */ : 0) | - (spec.error ? 4 /* Error */ : 0) | (spec.name == null ? 8 /* Anonymous */ : 0); - let type = new NodeType(spec.name || "", props, spec.id, flags); - if (spec.props) - for (let src of spec.props) { - if (!Array.isArray(src)) - src = src(type); - if (src) { - if (src[0].perNode) - throw new RangeError("Can't store a per-node prop on a node type"); - props[src[0].id] = src[1]; - } - } - return type; - } - /// Retrieves a node prop for this type. Will return `undefined` if - /// the prop isn't present on this node. - prop(prop) { return this.props[prop.id]; } - /// True when this is the top node of a grammar. - get isTop() { return (this.flags & 1 /* Top */) > 0; } - /// True when this node is produced by a skip rule. - get isSkipped() { return (this.flags & 2 /* Skipped */) > 0; } - /// Indicates whether this is an error node. - get isError() { return (this.flags & 4 /* Error */) > 0; } - /// When true, this node type doesn't correspond to a user-declared - /// named node, for example because it is used to cache repetition. - get isAnonymous() { return (this.flags & 8 /* Anonymous */) > 0; } - /// Returns true when this node's name or one of its - /// [groups](#common.NodeProp^group) matches the given string. - is(name) { - if (typeof name == 'string') { - if (this.name == name) - return true; - let group = this.prop(NodeProp.group); - return group ? group.indexOf(name) > -1 : false; - } - return this.id == name; - } - /// Create a function from node types to arbitrary values by - /// specifying an object whose property names are node or - /// [group](#common.NodeProp^group) names. Often useful with - /// [`NodeProp.add`](#common.NodeProp.add). You can put multiple - /// names, separated by spaces, in a single property name to map - /// multiple node names to a single value. - static match(map) { - let direct = Object.create(null); - for (let prop in map) - for (let name of prop.split(" ")) - direct[name] = map[prop]; - return (node) => { - for (let groups = node.prop(NodeProp.group), i = -1; i < (groups ? groups.length : 0); i++) { - let found = direct[i < 0 ? node.name : groups[i]]; - if (found) - return found; - } - }; - } + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') } -/// An empty dummy node type to use when no actual type is available. -NodeType.none = new NodeType("", Object.create(null), 0, 8 /* Anonymous */); -/// A node set holds a collection of node types. It is used to -/// compactly represent trees by storing their type ids, rather than a -/// full pointer to the type object, in a numeric array. Each parser -/// [has](#lr.LRParser.nodeSet) a node set, and [tree -/// buffers](#common.TreeBuffer) can only store collections of nodes -/// from the same set. A set can have a maximum of 2**16 (65536) node -/// types in it, so that the ids fit into 16-bit typed array slots. -class NodeSet { - /// Create a set with the given types. The `id` property of each - /// type should correspond to its position within the array. - constructor( - /// The node types in this set, by id. - types) { - this.types = types; - for (let i = 0; i < types.length; i++) - if (types[i].id != i) - throw new RangeError("Node type ids should correspond to array positions when creating a node set"); - } - /// Create a copy of this set with some node properties added. The - /// arguments to this method should be created with - /// [`NodeProp.add`](#common.NodeProp.add). - extend(...props) { - let newTypes = []; - for (let type of this.types) { - let newProps = null; - for (let source of props) { - let add = source(type); - if (add) { - if (!newProps) - newProps = Object.assign({}, type.props); - newProps[add[0].id] = add[1]; - } - } - newTypes.push(newProps ? new NodeType(type.name, newProps, type.id, type.flags) : type); - } - return new NodeSet(newTypes); - } + +},{}],42:[function(require,module,exports){ + +},{}],43:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var R = typeof Reflect === 'object' ? Reflect : null +var ReflectApply = R && typeof R.apply === 'function' + ? R.apply + : function ReflectApply(target, receiver, args) { + return Function.prototype.apply.call(target, receiver, args); + } + +var ReflectOwnKeys +if (R && typeof R.ownKeys === 'function') { + ReflectOwnKeys = R.ownKeys +} else if (Object.getOwnPropertySymbols) { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target) + .concat(Object.getOwnPropertySymbols(target)); + }; +} else { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target); + }; } -const CachedNode = new WeakMap(), CachedInnerNode = new WeakMap(); -/// A piece of syntax tree. There are two ways to approach these -/// trees: the way they are actually stored in memory, and the -/// convenient way. -/// -/// Syntax trees are stored as a tree of `Tree` and `TreeBuffer` -/// objects. By packing detail information into `TreeBuffer` leaf -/// nodes, the representation is made a lot more memory-efficient. -/// -/// However, when you want to actually work with tree nodes, this -/// representation is very awkward, so most client code will want to -/// use the [`TreeCursor`](#common.TreeCursor) or -/// [`SyntaxNode`](#common.SyntaxNode) interface instead, which provides -/// a view on some part of this data structure, and can be used to -/// move around to adjacent nodes. -class Tree { - /// Construct a new tree. See also [`Tree.build`](#common.Tree^build). - constructor( - /// The type of the top node. - type, - /// This node's child nodes. - children, - /// The positions (offsets relative to the start of this tree) of - /// the children. - positions, - /// The total length of this tree - length, - /// Per-node [node props](#common.NodeProp) to associate with this node. - props) { - this.type = type; - this.children = children; - this.positions = positions; - this.length = length; - /// @internal - this.props = null; - if (props && props.length) { - this.props = Object.create(null); - for (let [prop, value] of props) - this.props[typeof prop == "number" ? prop : prop.id] = value; - } - } - /// @internal - toString() { - let mounted = this.prop(NodeProp.mounted); - if (mounted && !mounted.overlay) - return mounted.tree.toString(); - let children = ""; - for (let ch of this.children) { - let str = ch.toString(); - if (str) { - if (children) - children += ","; - children += str; - } - } - return !this.type.name ? children : - (/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) + - (children.length ? "(" + children + ")" : ""); - } - /// Get a [tree cursor](#common.TreeCursor) rooted at this tree. When - /// `pos` is given, the cursor is [moved](#common.TreeCursor.moveTo) - /// to the given position and side. - cursor(pos, side = 0) { - let scope = (pos != null && CachedNode.get(this)) || this.topNode; - let cursor = new TreeCursor(scope); - if (pos != null) { - cursor.moveTo(pos, side); - CachedNode.set(this, cursor._tree); - } - return cursor; - } - /// Get a [tree cursor](#common.TreeCursor) that, unlike regular - /// cursors, doesn't skip through - /// [anonymous](#common.NodeType.isAnonymous) nodes and doesn't - /// automatically enter mounted nodes. - fullCursor() { - return new TreeCursor(this.topNode, 1 /* Full */); - } - /// Get a [syntax node](#common.SyntaxNode) object for the top of the - /// tree. - get topNode() { - return new TreeNode(this, 0, 0, null); - } - /// Get the [syntax node](#common.SyntaxNode) at the given position. - /// If `side` is -1, this will move into nodes that end at the - /// position. If 1, it'll move into nodes that start at the - /// position. With 0, it'll only enter nodes that cover the position - /// from both sides. - resolve(pos, side = 0) { - let node = resolveNode(CachedNode.get(this) || this.topNode, pos, side, false); - CachedNode.set(this, node); - return node; - } - /// Like [`resolve`](#common.Tree.resolve), but will enter - /// [overlaid](#common.MountedTree.overlay) nodes, producing a syntax node - /// pointing into the innermost overlaid tree at the given position - /// (with parent links going through all parent structure, including - /// the host trees). - resolveInner(pos, side = 0) { - let node = resolveNode(CachedInnerNode.get(this) || this.topNode, pos, side, true); - CachedInnerNode.set(this, node); - return node; - } - /// Iterate over the tree and its children, calling `enter` for any - /// node that touches the `from`/`to` region (if given) before - /// running over such a node's children, and `leave` (if given) when - /// leaving the node. When `enter` returns `false`, that node will - /// not have its children iterated over (or `leave` called). - iterate(spec) { - let { enter, leave, from = 0, to = this.length } = spec; - for (let c = this.cursor(), get = () => c.node;;) { - let mustLeave = false; - if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c.type, c.from, c.to, get) !== false)) { - if (c.firstChild()) - continue; - if (!c.type.isAnonymous) - mustLeave = true; - } - for (;;) { - if (mustLeave && leave) - leave(c.type, c.from, c.to, get); - mustLeave = c.type.isAnonymous; - if (c.nextSibling()) - break; - if (!c.parent()) - return; - mustLeave = true; - } - } - } - /// Get the value of the given [node prop](#common.NodeProp) for this - /// node. Works with both per-node and per-type props. - prop(prop) { - return !prop.perNode ? this.type.prop(prop) : this.props ? this.props[prop.id] : undefined; - } - /// Returns the node's [per-node props](#common.NodeProp.perNode) in a - /// format that can be passed to the [`Tree`](#common.Tree) - /// constructor. - get propValues() { - let result = []; - if (this.props) - for (let id in this.props) - result.push([+id, this.props[id]]); - return result; - } - /// Balance the direct children of this tree, producing a copy of - /// which may have children grouped into subtrees with type - /// [`NodeType.none`](#common.NodeType^none). - balance(config = {}) { - return this.children.length <= 8 /* BranchFactor */ ? this : - balanceRange(NodeType.none, this.children, this.positions, 0, this.children.length, 0, this.length, (children, positions, length) => new Tree(this.type, children, positions, length, this.propValues), config.makeTree || ((children, positions, length) => new Tree(NodeType.none, children, positions, length))); - } - /// Build a tree from a postfix-ordered buffer of node information, - /// or a cursor over such a buffer. - static build(data) { return buildTree(data); } + +function ProcessEmitWarning(warning) { + if (console && console.warn) console.warn(warning); } -/// The empty tree -Tree.empty = new Tree(NodeType.none, [], [], 0); -class FlatBufferCursor { - constructor(buffer, index) { - this.buffer = buffer; - this.index = index; - } - get id() { return this.buffer[this.index - 4]; } - get start() { return this.buffer[this.index - 3]; } - get end() { return this.buffer[this.index - 2]; } - get size() { return this.buffer[this.index - 1]; } - get pos() { return this.index; } - next() { this.index -= 4; } - fork() { return new FlatBufferCursor(this.buffer, this.index); } + +var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { + return value !== value; } -/// Tree buffers contain (type, start, end, endIndex) quads for each -/// node. In such a buffer, nodes are stored in prefix order (parents -/// before children, with the endIndex of the parent indicating which -/// children belong to it) -class TreeBuffer { - /// Create a tree buffer. - constructor( - /// The buffer's content. - buffer, - /// The total length of the group of nodes in the buffer. - length, - /// The node set used in this buffer. - set) { - this.buffer = buffer; - this.length = length; - this.set = set; + +function EventEmitter() { + EventEmitter.init.call(this); +} +module.exports = EventEmitter; +module.exports.once = once; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._eventsCount = 0; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +function checkListener(listener) { + if (typeof listener !== 'function') { + throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); + } +} + +Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { + throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); } - /// @internal - get type() { return NodeType.none; } - /// @internal - toString() { - let result = []; - for (let index = 0; index < this.buffer.length;) { - result.push(this.childString(index)); - index = this.buffer[index + 3]; - } - return result.join(","); + defaultMaxListeners = arg; + } +}); + +EventEmitter.init = function() { + + if (this._events === undefined || + this._events === Object.getPrototypeOf(this)._events) { + this._events = Object.create(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +}; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { + throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); + } + this._maxListeners = n; + return this; +}; + +function _getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} + +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return _getMaxListeners(this); +}; + +EventEmitter.prototype.emit = function emit(type) { + var args = []; + for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); + var doError = (type === 'error'); + + var events = this._events; + if (events !== undefined) + doError = (doError && events.error === undefined); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + var er; + if (args.length > 0) + er = args[0]; + if (er instanceof Error) { + // Note: The comments on the `throw` lines are intentional, they show + // up in Node's output if this results in an unhandled exception. + throw er; // Unhandled 'error' event } - /// @internal - childString(index) { - let id = this.buffer[index], endIndex = this.buffer[index + 3]; - let type = this.set.types[id], result = type.name; - if (/\W/.test(result) && !type.isError) - result = JSON.stringify(result); - index += 4; - if (endIndex == index) - return result; - let children = []; - while (index < endIndex) { - children.push(this.childString(index)); - index = this.buffer[index + 3]; - } - return result + "(" + children.join(",") + ")"; + // At least give some kind of context to the user + var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); + err.context = er; + throw err; // Unhandled 'error' event + } + + var handler = events[type]; + + if (handler === undefined) + return false; + + if (typeof handler === 'function') { + ReflectApply(handler, this, args); + } else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + ReflectApply(listeners[i], this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + checkListener(listener); + + events = target._events; + if (events === undefined) { + events = target._events = Object.create(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener !== undefined) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; } - /// @internal - findChild(startIndex, endIndex, dir, pos, side) { - let { buffer } = this, pick = -1; - for (let i = startIndex; i != endIndex; i = buffer[i + 3]) { - if (checkSide(side, pos, buffer[i + 1], buffer[i + 2])) { - pick = i; - if (dir > 0) - break; - } - } - return pick; + existing = events[type]; + } + + if (existing === undefined) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + // If we've already got an array, just append. + } else if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); } - /// @internal - slice(startI, endI, from, to) { - let b = this.buffer; - let copy = new Uint16Array(endI - startI); - for (let i = startI, j = 0; i < endI;) { - copy[j++] = b[i++]; - copy[j++] = b[i++] - from; - copy[j++] = b[i++] - from; - copy[j++] = b[i++] - startI; - } - return new TreeBuffer(copy, to - from, this.set); + + // Check for listener leak + m = _getMaxListeners(target); + if (m > 0 && existing.length > m && !existing.warned) { + existing.warned = true; + // No error code for this since it is a Warning + // eslint-disable-next-line no-restricted-syntax + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' ' + String(type) + ' listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + ProcessEmitWarning(w); } + } + + return target; } -function checkSide(side, pos, from, to) { - switch (side) { - case -2 /* Before */: return from < pos; - case -1 /* AtOrBefore */: return to >= pos && from < pos; - case 0 /* Around */: return from < pos && to > pos; - case 1 /* AtOrAfter */: return from <= pos && to > pos; - case 2 /* After */: return to > pos; - case 4 /* DontCare */: return true; - } + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) + return this.listener.call(this.target); + return this.listener.apply(this.target, arguments); + } } -function enterUnfinishedNodesBefore(node, pos) { - let scan = node.childBefore(pos); - while (scan) { - let last = scan.lastChild; - if (!last || last.to != scan.to) + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + checkListener(listener); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; + +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + checkListener(listener); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + checkListener(listener); + + events = this._events; + if (events === undefined) + return this; + + list = events[type]; + if (list === undefined) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; break; - if (last.type.isError && last.from == last.to) { - node = scan; - scan = last.prevSibling; + } } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); else { - scan = last; + spliceOne(list, position); } - } - return node; -} -function resolveNode(node, pos, side, overlays) { - var _a; - // Move up to a node that actually holds the position, if possible - while (node.from == node.to || - (side < 1 ? node.from >= pos : node.from > pos) || - (side > -1 ? node.to <= pos : node.to < pos)) { - let parent = !overlays && node instanceof TreeNode && node.index < 0 ? null : node.parent; - if (!parent) - return node; - node = parent; - } - // Must go up out of overlays when those do not overlap with pos - if (overlays) - for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) { - if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side, true)) === null || _a === void 0 ? void 0 : _a.from) != scan.from) - node = parent; + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener !== undefined) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (events === undefined) + return this; + + // not listening for removeListener, no need to emit + if (events.removeListener === undefined) { + if (arguments.length === 0) { + this._events = Object.create(null); + this._eventsCount = 0; + } else if (events[type] !== undefined) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else + delete events[type]; } - for (;;) { - let inner = node.enter(pos, side, overlays); - if (!inner) - return node; - node = inner; - } -} -class TreeNode { - constructor(node, _from, - // Index in parent node, set to -1 if the node is not a direct child of _parent.node (overlay) - index, _parent) { - this.node = node; - this._from = _from; - this.index = index; - this._parent = _parent; - } - get type() { return this.node.type; } - get name() { return this.node.type.name; } - get from() { return this._from; } - get to() { return this._from + this.node.length; } - nextChild(i, dir, pos, side, mode = 0) { - for (let parent = this;;) { - for (let { children, positions } = parent.node, e = dir > 0 ? children.length : -1; i != e; i += dir) { - let next = children[i], start = positions[i] + parent._from; - if (!checkSide(side, pos, start, start + next.length)) - continue; - if (next instanceof TreeBuffer) { - if (mode & 2 /* NoEnterBuffer */) - continue; - let index = next.findChild(0, next.buffer.length, dir, pos - start, side); - if (index > -1) - return new BufferNode(new BufferContext(parent, next, i, start), null, index); - } - else if ((mode & 1 /* Full */) || (!next.type.isAnonymous || hasChild(next))) { - let mounted; - if (!(mode & 1 /* Full */) && next.props && (mounted = next.prop(NodeProp.mounted)) && !mounted.overlay) - return new TreeNode(mounted.tree, start, i, parent); - let inner = new TreeNode(next, start, i, parent); - return (mode & 1 /* Full */) || !inner.type.isAnonymous ? inner - : inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side); - } - } - if ((mode & 1 /* Full */) || !parent.type.isAnonymous) - return null; - if (parent.index >= 0) - i = parent.index + dir; - else - i = dir < 0 ? -1 : parent._parent.node.children.length; - parent = parent._parent; - if (!parent) - return null; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = Object.keys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); } - } - get firstChild() { return this.nextChild(0, 1, 0, 4 /* DontCare */); } - get lastChild() { return this.nextChild(this.node.children.length - 1, -1, 0, 4 /* DontCare */); } - childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* After */); } - childBefore(pos) { return this.nextChild(this.node.children.length - 1, -1, pos, -2 /* Before */); } - enter(pos, side, overlays = true, buffers = true) { - let mounted; - if (overlays && (mounted = this.node.prop(NodeProp.mounted)) && mounted.overlay) { - let rPos = pos - this.from; - for (let { from, to } of mounted.overlay) { - if ((side > 0 ? from <= rPos : from < rPos) && - (side < 0 ? to >= rPos : to > rPos)) - return new TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this); - } + this.removeAllListeners('removeListener'); + this._events = Object.create(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners !== undefined) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); } - return this.nextChild(0, 1, pos, side, buffers ? 0 : 2 /* NoEnterBuffer */); - } - nextSignificantParent() { - let val = this; - while (val.type.isAnonymous && val._parent) - val = val._parent; - return val; - } - get parent() { - return this._parent ? this._parent.nextSignificantParent() : null; - } - get nextSibling() { - return this._parent && this.index >= 0 ? this._parent.nextChild(this.index + 1, 1, 0, 4 /* DontCare */) : null; - } - get prevSibling() { - return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* DontCare */) : null; - } - get cursor() { return new TreeCursor(this); } - get tree() { return this.node; } - toTree() { return this.node; } - resolve(pos, side = 0) { - return resolveNode(this, pos, side, false); + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (events === undefined) + return []; + + var evlistener = events[type]; + if (evlistener === undefined) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? + unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events !== undefined) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener !== undefined) { + return evlistener.length; } - resolveInner(pos, side = 0) { - return resolveNode(this, pos, side, true); + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; +}; + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function spliceOne(list, index) { + for (; index + 1 < list.length; index++) + list[index] = list[index + 1]; + list.pop(); +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function once(emitter, name) { + return new Promise(function (resolve, reject) { + function errorListener(err) { + emitter.removeListener(name, resolver); + reject(err); } - enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); } - getChild(type, before = null, after = null) { - let r = getChildren(this, type, before, after); - return r.length ? r[0] : null; + + function resolver() { + if (typeof emitter.removeListener === 'function') { + emitter.removeListener('error', errorListener); + } + resolve([].slice.call(arguments)); + }; + + eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); + if (name !== 'error') { + addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); } - getChildren(type, before = null, after = null) { - return getChildren(this, type, before, after); + }); +} + +function addErrorHandlerIfEventEmitter(emitter, handler, flags) { + if (typeof emitter.on === 'function') { + eventTargetAgnosticAddListener(emitter, 'error', handler, flags); + } +} + +function eventTargetAgnosticAddListener(emitter, name, listener, flags) { + if (typeof emitter.on === 'function') { + if (flags.once) { + emitter.once(name, listener); + } else { + emitter.on(name, listener); + } + } else if (typeof emitter.addEventListener === 'function') { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we do not listen for `error` events here. + emitter.addEventListener(name, function wrapListener(arg) { + // IE does not have builtin `{ once: true }` support so we + // have to do it manually. + if (flags.once) { + emitter.removeEventListener(name, wrapListener); + } + listener(arg); + }); + } else { + throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); + } +} + +},{}],44:[function(require,module,exports){ +(function (Buffer){(function (){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + +'use strict' + +var base64 = require('base64-js') +var ieee754 = require('ieee754') + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +var K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. + */ +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() + +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} + +function typedArraySupport () { + // Can typed array instances can be augmented? + try { + var arr = new Uint8Array(1) + arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } + return arr.foo() === 42 + } catch (e) { + return false + } +} + +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer + } +}) + +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset + } +}) + +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + var buf = new Uint8Array(length) + buf.__proto__ = Buffer.prototype + return buf +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new TypeError( + 'The "string" argument must be of type string. Received type number' + ) } - /// @internal - toString() { return this.node.toString(); } + return allocUnsafe(arg) + } + return from(arg, encodingOrOffset, length) +} + +// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 +if (typeof Symbol !== 'undefined' && Symbol.species != null && + Buffer[Symbol.species] === Buffer) { + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + enumerable: false, + writable: false + }) +} + +Buffer.poolSize = 8192 // not used by this implementation + +function from (value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset) + } + + if (ArrayBuffer.isView(value)) { + return fromArrayLike(value) + } + + if (value == null) { + throw TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof value === 'number') { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) + } + + var valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) + } + + var b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from( + value[Symbol.toPrimitive]('string'), encodingOrOffset, length + ) + } + + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, encodingOrOffset, length) +} + +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Buffer.prototype.__proto__ = Uint8Array.prototype +Buffer.__proto__ = Uint8Array + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be of type number') + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } +} + +function alloc (size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) + } + return createBuffer(size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(size, fill, encoding) +} + +function allocUnsafe (size) { + assertSize(size) + return createBuffer(size < 0 ? 0 : checked(size) | 0) +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(size) +} + +function fromString (string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + + var length = byteLength(string, encoding) | 0 + var buf = createBuffer(length) + + var actual = buf.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual) + } + + return buf } -function getChildren(node, type, before, after) { - let cur = node.cursor, result = []; - if (!cur.firstChild()) - return result; - if (before != null) - while (!cur.type.is(before)) - if (!cur.nextSibling()) - return result; - for (;;) { - if (after != null && cur.type.is(after)) - return result; - if (cur.type.is(type)) - result.push(cur.node); - if (!cur.nextSibling()) - return after == null ? result : []; - } + +function fromArrayLike (array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + var buf = createBuffer(length) + for (var i = 0; i < length; i += 1) { + buf[i] = array[i] & 255 + } + return buf } -class BufferContext { - constructor(parent, buffer, index, start) { - this.parent = parent; - this.buffer = buffer; - this.index = index; - this.start = start; - } + +function fromArrayBuffer (array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds') + } + + var buf + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array) + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset) + } else { + buf = new Uint8Array(array, byteOffset, length) + } + + // Return an augmented `Uint8Array` instance + buf.__proto__ = Buffer.prototype + return buf } -class BufferNode { - constructor(context, _parent, index) { - this.context = context; - this._parent = _parent; - this.index = index; - this.type = context.buffer.set.types[context.buffer.buffer[index]]; - } - get name() { return this.type.name; } - get from() { return this.context.start + this.context.buffer.buffer[this.index + 1]; } - get to() { return this.context.start + this.context.buffer.buffer[this.index + 2]; } - child(dir, pos, side) { - let { buffer } = this.context; - let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.context.start, side); - return index < 0 ? null : new BufferNode(this.context, this, index); - } - get firstChild() { return this.child(1, 0, 4 /* DontCare */); } - get lastChild() { return this.child(-1, 0, 4 /* DontCare */); } - childAfter(pos) { return this.child(1, pos, 2 /* After */); } - childBefore(pos) { return this.child(-1, pos, -2 /* Before */); } - enter(pos, side, overlays, buffers = true) { - if (!buffers) - return null; - let { buffer } = this.context; - let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side); - return index < 0 ? null : new BufferNode(this.context, this, index); - } - get parent() { - return this._parent || this.context.parent.nextSignificantParent(); - } - externalSibling(dir) { - return this._parent ? null : this.context.parent.nextChild(this.context.index + dir, dir, 0, 4 /* DontCare */); - } - get nextSibling() { - let { buffer } = this.context; - let after = buffer.buffer[this.index + 3]; - if (after < (this._parent ? buffer.buffer[this._parent.index + 3] : buffer.buffer.length)) - return new BufferNode(this.context, this._parent, after); - return this.externalSibling(1); - } - get prevSibling() { - let { buffer } = this.context; - let parentStart = this._parent ? this._parent.index + 4 : 0; - if (this.index == parentStart) - return this.externalSibling(-1); - return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */)); - } - get cursor() { return new TreeCursor(this); } - get tree() { return null; } - toTree() { - let children = [], positions = []; - let { buffer } = this.context; - let startI = this.index + 4, endI = buffer.buffer[this.index + 3]; - if (endI > startI) { - let from = buffer.buffer[this.index + 1], to = buffer.buffer[this.index + 2]; - children.push(buffer.slice(startI, endI, from, to)); - positions.push(0); - } - return new Tree(this.type, children, positions, this.to - this.from); - } - resolve(pos, side = 0) { - return resolveNode(this, pos, side, false); - } - resolveInner(pos, side = 0) { - return resolveNode(this, pos, side, true); - } - enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); } - /// @internal - toString() { return this.context.buffer.childString(this.index); } - getChild(type, before = null, after = null) { - let r = getChildren(this, type, before, after); - return r.length ? r[0] : null; + +function fromObject (obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0 + var buf = createBuffer(len) + + if (buf.length === 0) { + return buf } - getChildren(type, before = null, after = null) { - return getChildren(this, type, before, after); + + obj.copy(buf, 0, 0, len) + return buf + } + + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) } + return fromArrayLike(obj) + } + + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } } -/// A tree cursor object focuses on a given node in a syntax tree, and -/// allows you to move to adjacent nodes. -class TreeCursor { - /// @internal - constructor(node, - /// @internal - mode = 0) { - this.mode = mode; - this.buffer = null; - this.stack = []; - this.index = 0; - this.bufferNode = null; - if (node instanceof TreeNode) { - this.yieldNode(node); - } - else { - this._tree = node.context.parent; - this.buffer = node.context; - for (let n = node._parent; n; n = n._parent) - this.stack.unshift(n.index); - this.bufferNode = node; - this.yieldBuf(node.index); - } - } - /// Shorthand for `.type.name`. - get name() { return this.type.name; } - yieldNode(node) { - if (!node) - return false; - this._tree = node; - this.type = node.type; - this.from = node.from; - this.to = node.to; - return true; - } - yieldBuf(index, type) { - this.index = index; - let { start, buffer } = this.buffer; - this.type = type || buffer.set.types[buffer.buffer[index]]; - this.from = start + buffer.buffer[index + 1]; - this.to = start + buffer.buffer[index + 2]; - return true; - } - yield(node) { - if (!node) - return false; - if (node instanceof TreeNode) { - this.buffer = null; - return this.yieldNode(node); - } - this.buffer = node.context; - return this.yieldBuf(node.index, node.type); - } - /// @internal - toString() { - return this.buffer ? this.buffer.buffer.childString(this.index) : this._tree.toString(); - } - /// @internal - enterChild(dir, pos, side) { - if (!this.buffer) - return this.yield(this._tree.nextChild(dir < 0 ? this._tree.node.children.length - 1 : 0, dir, pos, side, this.mode)); - let { buffer } = this.buffer; - let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side); - if (index < 0) - return false; - this.stack.push(this.index); - return this.yieldBuf(index); - } - /// Move the cursor to this node's first child. When this returns - /// false, the node has no child, and the cursor has not been moved. - firstChild() { return this.enterChild(1, 0, 4 /* DontCare */); } - /// Move the cursor to this node's last child. - lastChild() { return this.enterChild(-1, 0, 4 /* DontCare */); } - /// Move the cursor to the first child that ends after `pos`. - childAfter(pos) { return this.enterChild(1, pos, 2 /* After */); } - /// Move to the last child that starts before `pos`. - childBefore(pos) { return this.enterChild(-1, pos, -2 /* Before */); } - /// Move the cursor to the child around `pos`. If side is -1 the - /// child may end at that position, when 1 it may start there. This - /// will also enter [overlaid](#common.MountedTree.overlay) - /// [mounted](#common.NodeProp^mounted) trees unless `overlays` is - /// set to false. - enter(pos, side, overlays = true, buffers = true) { - if (!this.buffer) - return this.yield(this._tree.enter(pos, side, overlays && !(this.mode & 1 /* Full */), buffers)); - return buffers ? this.enterChild(1, pos, side) : false; - } - /// Move to the node's parent node, if this isn't the top node. - parent() { - if (!this.buffer) - return this.yieldNode((this.mode & 1 /* Full */) ? this._tree._parent : this._tree.parent); - if (this.stack.length) - return this.yieldBuf(this.stack.pop()); - let parent = (this.mode & 1 /* Full */) ? this.buffer.parent : this.buffer.parent.nextSignificantParent(); - this.buffer = null; - return this.yieldNode(parent); - } - /// @internal - sibling(dir) { - if (!this.buffer) - return !this._tree._parent ? false - : this.yield(this._tree.index < 0 ? null - : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4 /* DontCare */, this.mode)); - let { buffer } = this.buffer, d = this.stack.length - 1; - if (dir < 0) { - let parentStart = d < 0 ? 0 : this.stack[d] + 4; - if (this.index != parentStart) - return this.yieldBuf(buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */)); - } - else { - let after = buffer.buffer[this.index + 3]; - if (after < (d < 0 ? buffer.buffer.length : buffer.buffer[this.stack[d] + 3])) - return this.yieldBuf(after); - } - return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4 /* DontCare */, this.mode)) : false; - } - /// Move to this node's next sibling, if any. - nextSibling() { return this.sibling(1); } - /// Move to this node's previous sibling, if any. - prevSibling() { return this.sibling(-1); } - atLastNode(dir) { - let index, parent, { buffer } = this; - if (buffer) { - if (dir > 0) { - if (this.index < buffer.buffer.buffer.length) - return false; - } - else { - for (let i = 0; i < this.index; i++) - if (buffer.buffer.buffer[i + 3] < this.index) - return false; - } - ({ index, parent } = buffer); - } - else { - ({ index, _parent: parent } = this._tree); - } - for (; parent; { index, _parent: parent } = parent) { - if (index > -1) - for (let i = index + dir, e = dir < 0 ? -1 : parent.node.children.length; i != e; i += dir) { - let child = parent.node.children[i]; - if ((this.mode & 1 /* Full */) || child instanceof TreeBuffer || !child.type.isAnonymous || hasChild(child)) - return false; - } - } - return true; - } - move(dir, enter) { - if (enter && this.enterChild(dir, 0, 4 /* DontCare */)) - return true; - for (;;) { - if (this.sibling(dir)) - return true; - if (this.atLastNode(dir) || !this.parent()) - return false; - } - } - /// Move to the next node in a - /// [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR)) - /// traversal, going from a node to its first child or, if the - /// current node is empty or `enter` is false, its next sibling or - /// the next sibling of the first parent node that has one. - next(enter = true) { return this.move(1, enter); } - /// Move to the next node in a last-to-first pre-order traveral. A - /// node is followed by its last child or, if it has none, its - /// previous sibling or the previous sibling of the first parent - /// node that has one. - prev(enter = true) { return this.move(-1, enter); } - /// Move the cursor to the innermost node that covers `pos`. If - /// `side` is -1, it will enter nodes that end at `pos`. If it is 1, - /// it will enter nodes that start at `pos`. - moveTo(pos, side = 0) { - // Move up to a node that actually holds the position, if possible - while (this.from == this.to || - (side < 1 ? this.from >= pos : this.from > pos) || - (side > -1 ? this.to <= pos : this.to < pos)) - if (!this.parent()) - break; - // Then scan down into child nodes as far as possible - while (this.enterChild(1, pos, side)) { } - return this; - } - /// Get a [syntax node](#common.SyntaxNode) at the cursor's current - /// position. - get node() { - if (!this.buffer) - return this._tree; - let cache = this.bufferNode, result = null, depth = 0; - if (cache && cache.context == this.buffer) { - scan: for (let index = this.index, d = this.stack.length; d >= 0;) { - for (let c = cache; c; c = c._parent) - if (c.index == index) { - if (index == this.index) - return c; - result = c; - depth = d + 1; - break scan; - } - index = this.stack[--d]; - } - } - for (let i = depth; i < this.stack.length; i++) - result = new BufferNode(this.buffer, result, this.stack[i]); - return this.bufferNode = new BufferNode(this.buffer, result, this.index); - } - /// Get the [tree](#common.Tree) that represents the current node, if - /// any. Will return null when the node is in a [tree - /// buffer](#common.TreeBuffer). - get tree() { - return this.buffer ? null : this._tree.node; - } + +function checked (length) { + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= K_MAX_LENGTH) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') + } + return length | 0 } -function hasChild(tree) { - return tree.children.some(ch => ch instanceof TreeBuffer || !ch.type.isAnonymous || hasChild(ch)); + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) } -function buildTree(data) { - var _a; - let { buffer, nodeSet, maxBufferLength = DefaultBufferLength, reused = [], minRepeatType = nodeSet.types.length } = data; - let cursor = Array.isArray(buffer) ? new FlatBufferCursor(buffer, buffer.length) : buffer; - let types = nodeSet.types; - let contextHash = 0, lookAhead = 0; - function takeNode(parentStart, minPos, children, positions, inRepeat) { - let { id, start, end, size } = cursor; - let lookAheadAtStart = lookAhead; - while (size < 0) { - cursor.next(); - if (size == -1 /* Reuse */) { - let node = reused[id]; - children.push(node); - positions.push(start - parentStart); - return; - } - else if (size == -3 /* ContextChange */) { // Context change - contextHash = id; - return; - } - else if (size == -4 /* LookAhead */) { - lookAhead = id; - return; - } - else { - throw new RangeError(`Unrecognized record size: ${size}`); - } - } - let type = types[id], node, buffer; - let startPos = start - parentStart; - if (end - start <= maxBufferLength && (buffer = findBufferSize(cursor.pos - minPos, inRepeat))) { - // Small enough for a buffer, and no reused nodes inside - let data = new Uint16Array(buffer.size - buffer.skip); - let endPos = cursor.pos - buffer.size, index = data.length; - while (cursor.pos > endPos) - index = copyToBuffer(buffer.start, data, index); - node = new TreeBuffer(data, end - buffer.start, nodeSet); - startPos = buffer.start - parentStart; - } - else { // Make it a node - let endPos = cursor.pos - size; - cursor.next(); - let localChildren = [], localPositions = []; - let localInRepeat = id >= minRepeatType ? id : -1; - let lastGroup = 0, lastEnd = end; - while (cursor.pos > endPos) { - if (localInRepeat >= 0 && cursor.id == localInRepeat && cursor.size >= 0) { - if (cursor.end <= lastEnd - maxBufferLength) { - makeRepeatLeaf(localChildren, localPositions, start, lastGroup, cursor.end, lastEnd, localInRepeat, lookAheadAtStart); - lastGroup = localChildren.length; - lastEnd = cursor.end; - } - cursor.next(); - } - else { - takeNode(start, endPos, localChildren, localPositions, localInRepeat); - } - } - if (localInRepeat >= 0 && lastGroup > 0 && lastGroup < localChildren.length) - makeRepeatLeaf(localChildren, localPositions, start, lastGroup, start, lastEnd, localInRepeat, lookAheadAtStart); - localChildren.reverse(); - localPositions.reverse(); - if (localInRepeat > -1 && lastGroup > 0) { - let make = makeBalanced(type); - node = balanceRange(type, localChildren, localPositions, 0, localChildren.length, 0, end - start, make, make); - } - else { - node = makeTree(type, localChildren, localPositions, end - start, lookAheadAtStart - end); - } - } - children.push(node); - positions.push(startPos); - } - function makeBalanced(type) { - return (children, positions, length) => { - let lookAhead = 0, lastI = children.length - 1, last, lookAheadProp; - if (lastI >= 0 && (last = children[lastI]) instanceof Tree) { - if (!lastI && last.type == type && last.length == length) - return last; - if (lookAheadProp = last.prop(NodeProp.lookAhead)) - lookAhead = positions[lastI] + last.length + lookAheadProp; - } - return makeTree(type, children, positions, length, lookAhead); - }; - } - function makeRepeatLeaf(children, positions, base, i, from, to, type, lookAhead) { - let localChildren = [], localPositions = []; - while (children.length > i) { - localChildren.push(children.pop()); - localPositions.push(positions.pop() + base - from); - } - children.push(makeTree(nodeSet.types[type], localChildren, localPositions, to - from, lookAhead - to)); - positions.push(from - base); + +Buffer.isBuffer = function isBuffer (b) { + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false +} + +Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) + } + + if (a === b) return 0 + + var x = a.length + var y = b.length + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break } - function makeTree(type, children, positions, length, lookAhead = 0, props) { - if (contextHash) { - let pair = [NodeProp.contextHash, contextHash]; - props = props ? [pair].concat(props) : [pair]; - } - if (lookAhead > 25) { - let pair = [NodeProp.lookAhead, lookAhead]; - props = props ? [pair].concat(props) : [pair]; - } - return new Tree(type, children, positions, length, props); + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length } - function findBufferSize(maxSize, inRepeat) { - // Scan through the buffer to find previous siblings that fit - // together in a TreeBuffer, and don't contain any reused nodes - // (which can't be stored in a buffer). - // If `inRepeat` is > -1, ignore node boundaries of that type for - // nesting, but make sure the end falls either at the start - // (`maxSize`) or before such a node. - let fork = cursor.fork(); - let size = 0, start = 0, skip = 0, minStart = fork.end - maxBufferLength; - let result = { size: 0, start: 0, skip: 0 }; - scan: for (let minPos = fork.pos - maxSize; fork.pos > minPos;) { - let nodeSize = fork.size; - // Pretend nested repeat nodes of the same type don't exist - if (fork.id == inRepeat && nodeSize >= 0) { - // Except that we store the current state as a valid return - // value. - result.size = size; - result.start = start; - result.skip = skip; - skip += 4; - size += 4; - fork.next(); - continue; - } - let startPos = fork.pos - nodeSize; - if (nodeSize < 0 || startPos < minPos || fork.start < minStart) - break; - let localSkipped = fork.id >= minRepeatType ? 4 : 0; - let nodeStart = fork.start; - fork.next(); - while (fork.pos > startPos) { - if (fork.size < 0) { - if (fork.size == -3 /* ContextChange */) - localSkipped += 4; - else - break scan; - } - else if (fork.id >= minRepeatType) { - localSkipped += 4; - } - fork.next(); - } - start = nodeStart; - size += nodeSize; - skip += localSkipped; - } - if (inRepeat < 0 || size == maxSize) { - result.size = size; - result.start = start; - result.skip = skip; - } - return result.size > 4 ? result : undefined; + } + + var buffer = Buffer.allocUnsafe(length) + var pos = 0 + for (i = 0; i < list.length; ++i) { + var buf = list[i] + if (isInstance(buf, Uint8Array)) { + buf = Buffer.from(buf) } - function copyToBuffer(bufferStart, buffer, index) { - let { id, start, end, size } = cursor; - cursor.next(); - if (size >= 0 && id < minRepeatType) { - let startIndex = index; - if (size > 4) { - let endPos = cursor.pos - (size - 4); - while (cursor.pos > endPos) - index = copyToBuffer(bufferStart, buffer, index); - } - buffer[--index] = startIndex; - buffer[--index] = end - bufferStart; - buffer[--index] = start - bufferStart; - buffer[--index] = id; - } - else if (size == -3 /* ContextChange */) { - contextHash = id; - } - else if (size == -4 /* LookAhead */) { - lookAhead = id; - } - return index; + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') } - let children = [], positions = []; - while (cursor.pos > 0) - takeNode(data.start || 0, data.bufferStart || 0, children, positions, -1); - let length = (_a = data.length) !== null && _a !== void 0 ? _a : (children.length ? positions[0] + children[0].length : 0); - return new Tree(types[data.topID], children.reverse(), positions.reverse(), length); + buf.copy(buffer, pos) + pos += buf.length + } + return buffer } -const nodeSizeCache = new WeakMap; -function nodeSize(balanceType, node) { - if (!balanceType.isAnonymous || node instanceof TreeBuffer || node.type != balanceType) - return 1; - let size = nodeSizeCache.get(node); - if (size == null) { - size = 1; - for (let child of node.children) { - if (child.type != balanceType || !(child instanceof Tree)) { - size = 1; - break; - } - size += nodeSize(balanceType, child); + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) + } + + var len = string.length + var mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 } - nodeSizeCache.set(node, size); + encoding = ('' + encoding).toLowerCase() + loweredCase = true } - return size; + } } -function balanceRange( -// The type the balanced tree's inner nodes. -balanceType, -// The direct children and their positions -children, positions, -// The index range in children/positions to use -from, to, -// The start position of the nodes, relative to their parent. -start, -// Length of the outer node -length, -// Function to build the top node of the balanced tree -mkTop, -// Function to build internal nodes for the balanced tree -mkTree) { - let total = 0; - for (let i = from; i < to; i++) - total += nodeSize(balanceType, children[i]); - let maxChild = Math.ceil((total * 1.5) / 8 /* BranchFactor */); - let localChildren = [], localPositions = []; - function divide(children, positions, from, to, offset) { - for (let i = from; i < to;) { - let groupFrom = i, groupStart = positions[i], groupSize = nodeSize(balanceType, children[i]); - i++; - for (; i < to; i++) { - let nextSize = nodeSize(balanceType, children[i]); - if (groupSize + nextSize >= maxChild) - break; - groupSize += nextSize; - } - if (i == groupFrom + 1) { - if (groupSize > maxChild) { - let only = children[groupFrom]; // Only trees can have a size > 1 - divide(only.children, only.positions, 0, only.children.length, positions[groupFrom] + offset); - continue; - } - localChildren.push(children[groupFrom]); - } - else { - let length = positions[i - 1] + children[i - 1].length - groupStart; - localChildren.push(balanceRange(balanceType, children, positions, groupFrom, i, groupStart, length, null, mkTree)); - } - localPositions.push(groupStart + offset - start); - } +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + var loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true } - divide(children, positions, from, to, 0); - return (mkTop || mkTree)(localChildren, localPositions, length); + } } -/// Tree fragments are used during [incremental -/// parsing](#common.Parser.startParse) to track parts of old trees -/// that can be reused in a new parse. An array of fragments is used -/// to track regions of an old tree whose nodes might be reused in new -/// parses. Use the static -/// [`applyChanges`](#common.TreeFragment^applyChanges) method to -/// update fragments for document changes. -class TreeFragment { - /// Construct a tree fragment. - constructor( - /// The start of the unchanged range pointed to by this fragment. - /// This refers to an offset in the _updated_ document (as opposed - /// to the original tree). - from, - /// The end of the unchanged range. - to, - /// The tree that this fragment is based on. - tree, - /// The offset between the fragment's tree and the document that - /// this fragment can be used against. Add this when going from - /// document to tree positions, subtract it to go from tree to - /// document positions. - offset, openStart = false, openEnd = false) { - this.from = from; - this.to = to; - this.tree = tree; - this.offset = offset; - this.open = (openStart ? 1 /* Start */ : 0) | (openEnd ? 2 /* End */ : 0); +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + var i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + var len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + var len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + var length = this.length + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.toLocaleString = Buffer.prototype.toString + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' + return '' +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } + if (!Buffer.isBuffer(target)) { + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + var x = thisEnd - thisStart + var y = end - start + var len = Math.min(x, y) + + var thisCopy = this.slice(thisStart, thisEnd) + var targetCopy = target.slice(start, end) + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break } - /// Whether the start of the fragment represents the start of a - /// parse, or the end of a change. (In the second case, it may not - /// be safe to reuse some nodes at the start, depending on the - /// parsing algorithm.) - get openStart() { return (this.open & 1 /* Start */) > 0; } - /// Whether the end of the fragment represents the end of a - /// full-document parse, or the start of a change. - get openEnd() { return (this.open & 2 /* End */) > 0; } - /// Create a set of fragments from a freshly parsed tree, or update - /// an existing set of fragments by replacing the ones that overlap - /// with a tree with content from the new tree. When `partial` is - /// true, the parse is treated as incomplete, and the resulting - /// fragment has [`openEnd`](#common.TreeFragment.openEnd) set to - /// true. - static addTree(tree, fragments = [], partial = false) { - let result = [new TreeFragment(0, tree.length, tree, 0, false, partial)]; - for (let f of fragments) - if (f.to > tree.length) - result.push(f); - return result; + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 } - /// Apply a set of edits to an array of fragments, removing or - /// splitting fragments as necessary to remove edited ranges, and - /// adjusting offsets for fragments that moved. - static applyChanges(fragments, changes, minGap = 128) { - if (!changes.length) - return fragments; - let result = []; - let fI = 1, nextF = fragments.length ? fragments[0] : null; - for (let cI = 0, pos = 0, off = 0;; cI++) { - let nextC = cI < changes.length ? changes[cI] : null; - let nextPos = nextC ? nextC.fromA : 1e9; - if (nextPos - pos >= minGap) - while (nextF && nextF.from < nextPos) { - let cut = nextF; - if (pos >= cut.from || nextPos <= cut.to || off) { - let fFrom = Math.max(cut.from, pos) - off, fTo = Math.min(cut.to, nextPos) - off; - cut = fFrom >= fTo ? null : new TreeFragment(fFrom, fTo, cut.tree, cut.offset + off, cI > 0, !!nextC); - } - if (cut) - result.push(cut); - if (nextF.to > nextPos) - break; - nextF = fI < fragments.length ? fragments[fI++] : null; - } - if (!nextC) - break; - pos = nextC.toA; - off = nextC.toA - nextC.toB; - } - return result; + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') } -/// A superclass that parsers should extend. -class Parser { - /// Start a parse, returning a [partial parse](#common.PartialParse) - /// object. [`fragments`](#common.TreeFragment) can be passed in to - /// make the parse incremental. - /// - /// By default, the entire input is parsed. You can pass `ranges`, - /// which should be a sorted array of non-empty, non-overlapping - /// ranges, to parse only those ranges. The tree returned in that - /// case will start at `ranges[0].from`. - startParse(input, fragments, ranges) { - if (typeof input == "string") - input = new StringInput(input); - ranges = !ranges ? [new Range(0, input.length)] : ranges.length ? ranges.map(r => new Range(r.from, r.to)) : [new Range(0, 0)]; - return this.createParse(input, fragments || [], ranges); + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1 + var arrLength = arr.length + var valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 } - /// Run a full parse, returning the resulting tree. - parse(input, fragments, ranges) { - let parse = this.startParse(input, fragments, ranges); - for (;;) { - let done = parse.advance(); - if (done) - return done; + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break } + } + if (found) return i } + } + + return -1 } -class StringInput { - constructor(string) { - this.string = string; - } - get length() { return this.string.length; } - chunk(from) { return this.string.slice(from); } - get lineChunks() { return false; } - read(from, to) { return this.string.slice(from, to); } + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 } -/// Create a parse wrapper that, after the inner parse completes, -/// scans its tree for mixed language regions with the `nest` -/// function, runs the resulting [inner parses](#common.NestedParse), -/// and then [mounts](#common.NodeProp^mounted) their results onto the -/// tree. -/// -/// The nesting function is passed a cursor to provide context for a -/// node, but _should not_ move that cursor, only inspect its -/// properties and optionally access its -/// [node object](#common.TreeCursor.node). -function parseMixed(nest) { - return (parse, input, fragments, ranges) => new MixedParse(parse, nest, input, fragments, ranges); +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) } -class InnerParse { - constructor(parser, parse, overlay, target, ranges) { - this.parser = parser; - this.parse = parse; - this.overlay = overlay; - this.target = target; - this.ranges = ranges; - } + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) } -class ActiveOverlay { - constructor(parser, predicate, mounts, index, start, target, prev) { - this.parser = parser; - this.predicate = predicate; - this.mounts = mounts; - this.index = index; - this.start = start; - this.target = target; - this.prev = prev; - this.depth = 0; - this.ranges = []; + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining } + } + + var strLen = string.length + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16) + if (numberIsNaN(parsed)) return i + buf[offset + i] = parsed + } + return i } -const stoppedInner = new NodeProp({ perNode: true }); -class MixedParse { - constructor(base, nest, input, fragments, ranges) { - this.nest = nest; - this.input = input; - this.fragments = fragments; - this.ranges = ranges; - this.inner = []; - this.innerDone = 0; - this.baseTree = null; - this.stoppedAt = null; - this.baseParse = base; - } - advance() { - if (this.baseParse) { - let done = this.baseParse.advance(); - if (!done) - return null; - this.baseParse = null; - this.baseTree = done; - this.startInner(); - if (this.stoppedAt != null) - for (let inner of this.inner) - inner.parse.stopAt(this.stoppedAt); - } - if (this.innerDone == this.inner.length) { - let result = this.baseTree; - if (this.stoppedAt != null) - result = new Tree(result.type, result.children, result.positions, result.length, result.propValues.concat([[stoppedInner, this.stoppedAt]])); - return result; - } - let inner = this.inner[this.innerDone], done = inner.parse.advance(); - if (done) { - this.innerDone++; - // This is a somewhat dodgy but super helpful hack where we - // patch up nodes created by the inner parse (and thus - // presumably not aliased anywhere else) to hold the information - // about the inner parse. - let props = Object.assign(Object.create(null), inner.target.props); - props[NodeProp.mounted.id] = new MountedTree(done, inner.overlay, inner.parser); - inner.target.props = props; - } - return null; - } - get parsedPos() { - if (this.baseParse) - return 0; - let pos = this.input.length; - for (let i = this.innerDone; i < this.inner.length; i++) { - if (this.inner[i].ranges[0].from < pos) - pos = Math.min(pos, this.inner[i].parse.parsedPos); - } - return pos; - } - stopAt(pos) { - this.stoppedAt = pos; - if (this.baseParse) - this.baseParse.stopAt(pos); - else - for (let i = this.innerDone; i < this.inner.length; i++) - this.inner[i].parse.stopAt(pos); - } - startInner() { - let fragmentCursor = new FragmentCursor(this.fragments); - let overlay = null; - let covered = null; - let cursor = new TreeCursor(new TreeNode(this.baseTree, this.ranges[0].from, 0, null), 1 /* Full */); - scan: for (let nest, isCovered; this.stoppedAt == null || cursor.from < this.stoppedAt;) { - let enter = true, range; - if (fragmentCursor.hasNode(cursor)) { - if (overlay) { - let match = overlay.mounts.find(m => m.frag.from <= cursor.from && m.frag.to >= cursor.to && m.mount.overlay); - if (match) - for (let r of match.mount.overlay) { - let from = r.from + match.pos, to = r.to + match.pos; - if (from >= cursor.from && to <= cursor.to) - overlay.ranges.push({ from, to }); - } - } - enter = false; - } - else if (covered && (isCovered = checkCover(covered.ranges, cursor.from, cursor.to))) { - enter = isCovered != 2 /* Full */; - } - else if (!cursor.type.isAnonymous && cursor.from < cursor.to && (nest = this.nest(cursor, this.input))) { - if (!cursor.tree) - materialize(cursor); - let oldMounts = fragmentCursor.findMounts(cursor.from, nest.parser); - if (typeof nest.overlay == "function") { - overlay = new ActiveOverlay(nest.parser, nest.overlay, oldMounts, this.inner.length, cursor.from, cursor.tree, overlay); - } - else { - let ranges = punchRanges(this.ranges, nest.overlay || [new Range(cursor.from, cursor.to)]); - if (ranges.length) - this.inner.push(new InnerParse(nest.parser, nest.parser.startParse(this.input, enterFragments(oldMounts, ranges), ranges), nest.overlay ? nest.overlay.map(r => new Range(r.from - cursor.from, r.to - cursor.from)) : null, cursor.tree, ranges)); - if (!nest.overlay) - enter = false; - else if (ranges.length) - covered = { ranges, depth: 0, prev: covered }; - } - } - else if (overlay && (range = overlay.predicate(cursor))) { - if (range === true) - range = new Range(cursor.from, cursor.to); - if (range.from < range.to) - overlay.ranges.push(range); - } - if (enter && cursor.firstChild()) { - if (overlay) - overlay.depth++; - if (covered) - covered.depth++; - } - else { - for (;;) { - if (cursor.nextSibling()) - break; - if (!cursor.parent()) - break scan; - if (overlay && !--overlay.depth) { - let ranges = punchRanges(this.ranges, overlay.ranges); - if (ranges.length) - this.inner.splice(overlay.index, 0, new InnerParse(overlay.parser, overlay.parser.startParse(this.input, enterFragments(overlay.mounts, ranges), ranges), overlay.ranges.map(r => new Range(r.from - overlay.start, r.to - overlay.start)), overlay.target, ranges)); - overlay = overlay.prev; - } - if (covered && !--covered.depth) - covered = covered.prev; - } - } - } - } + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) } -function checkCover(covered, from, to) { - for (let range of covered) { - if (range.from >= to) - break; - if (range.to > from) - return range.from <= from && range.to >= to ? 2 /* Full */ : 1 /* Partial */; - } - return 0 /* None */; + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) } -// Take a piece of buffer and convert it into a stand-alone -// TreeBuffer. -function sliceBuf(buf, startI, endI, nodes, positions, off) { - if (startI < endI) { - let from = buf.buffer[startI + 1], to = buf.buffer[endI - 2]; - nodes.push(buf.slice(startI, endI, from, to)); - positions.push(from - off); - } + +function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) } -// This function takes a node that's in a buffer, and converts it, and -// its parent buffer nodes, into a Tree. This is again acting on the -// assumption that the trees and buffers have been constructed by the -// parse that was ran via the mix parser, and thus aren't shared with -// any other code, making violations of the immutability safe. -function materialize(cursor) { - let { node } = cursor, depth = 0; - // Scan up to the nearest tree - do { - cursor.parent(); - depth++; - } while (!cursor.tree); - // Find the index of the buffer in that tree - let i = 0, base = cursor.tree, off = 0; - for (;; i++) { - off = base.positions[i] + cursor.from; - if (off <= node.from && off + base.children[i].length >= node.to) - break; - } - let buf = base.children[i], b = buf.buffer; - // Split a level in the buffer, putting the nodes before and after - // the child that contains `node` into new buffers. - function split(startI, endI, type, innerOffset, length) { - let i = startI; - while (b[i + 2] + off <= node.from) - i = b[i + 3]; - let children = [], positions = []; - sliceBuf(buf, startI, i, children, positions, innerOffset); - let from = b[i + 1], to = b[i + 2]; - let isTarget = from + off == node.from && to + off == node.to && b[i] == node.type.id; - children.push(isTarget ? node.toTree() : split(i + 4, b[i + 3], buf.set.types[b[i]], from, to - from)); - positions.push(from - innerOffset); - sliceBuf(buf, b[i + 3], endI, children, positions, innerOffset); - return new Tree(type, children, positions, length); - } - base.children[i] = split(0, b.length, NodeType.none, 0, buf.length); - // Move the cursor back to the target node - for (let d = 0; d <= depth; d++) - cursor.childAfter(node.from); + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) } -class StructureCursor { - constructor(root, offset) { - this.offset = offset; - this.done = false; - this.cursor = root.fullCursor(); - } - // Move to the first node (in pre-order) that starts at or after `pos`. - moveTo(pos) { - let { cursor } = this, p = pos - this.offset; - while (!this.done && cursor.from < p) { - if (cursor.to >= pos && cursor.enter(p, 1, false, false)) ; - else if (!cursor.next(false)) - this.done = true; - } - } - hasNode(cursor) { - this.moveTo(cursor.from); - if (!this.done && this.cursor.from + this.offset == cursor.from && this.cursor.tree) { - for (let tree = this.cursor.tree;;) { - if (tree == cursor.tree) - return true; - if (tree.children.length && tree.positions[0] == 0 && tree.children[0] instanceof Tree) - tree = tree.children[0]; - else - break; - } - } - return false; - } + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) } -class FragmentCursor { - constructor(fragments) { - var _a; - this.fragments = fragments; - this.curTo = 0; - this.fragI = 0; - if (fragments.length) { - let first = this.curFrag = fragments[0]; - this.curTo = (_a = first.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : first.to; - this.inner = new StructureCursor(first.tree, -first.offset); - } - else { - this.curFrag = this.inner = null; - } - } - hasNode(node) { - while (this.curFrag && node.from >= this.curTo) - this.nextFrag(); - return this.curFrag && this.curFrag.from <= node.from && this.curTo >= node.to && this.inner.hasNode(node); - } - nextFrag() { - var _a; - this.fragI++; - if (this.fragI == this.fragments.length) { - this.curFrag = this.inner = null; - } - else { - let frag = this.curFrag = this.fragments[this.fragI]; - this.curTo = (_a = frag.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : frag.to; - this.inner = new StructureCursor(frag.tree, -frag.offset); - } - } - findMounts(pos, parser) { - var _a; - let result = []; - if (this.inner) { - this.inner.cursor.moveTo(pos, 1); - for (let pos = this.inner.cursor.node; pos; pos = pos.parent) { - let mount = (_a = pos.tree) === null || _a === void 0 ? void 0 : _a.prop(NodeProp.mounted); - if (mount && mount.parser == parser) { - for (let i = this.fragI; i < this.fragments.length; i++) { - let frag = this.fragments[i]; - if (frag.from >= pos.to) - break; - if (frag.tree == this.curFrag.tree) - result.push({ - frag, - pos: pos.from - frag.offset, - mount - }); - } - } - } - } - return result; + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset >>> 0 + if (isFinite(length)) { + length = length >>> 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + var loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true } + } } -function punchRanges(outer, ranges) { - let copy = null, current = ranges; - for (let i = 1, j = 0; i < outer.length; i++) { - let gapFrom = outer[i - 1].to, gapTo = outer[i].from; - for (; j < current.length; j++) { - let r = current[j]; - if (r.from >= gapTo) - break; - if (r.to <= gapFrom) - continue; - if (!copy) - current = copy = ranges.slice(); - if (r.from < gapFrom) { - copy[j] = new Range(r.from, gapFrom); - if (r.to > gapTo) - copy.splice(j + 1, 0, new Range(gapTo, r.to)); + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + var res = [] + + var i = start + while (i < end) { + var firstByte = buf[i] + var codePoint = null + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint } - else if (r.to > gapTo) { - copy[j--] = new Range(gapTo, r.to); + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint } - else { - copy.splice(j--, 1); + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint } - } + } + } } - return current; -} -function findCoverChanges(a, b, from, to) { - let iA = 0, iB = 0, inA = false, inB = false, pos = -1e9; - let result = []; - for (;;) { - let nextA = iA == a.length ? 1e9 : inA ? a[iA].to : a[iA].from; - let nextB = iB == b.length ? 1e9 : inB ? b[iB].to : b[iB].from; - if (inA != inB) { - let start = Math.max(pos, from), end = Math.min(nextA, nextB, to); - if (start < end) - result.push(new Range(start, end)); - } - pos = Math.min(nextA, nextB); - if (pos == 1e9) - break; - if (nextA == pos) { - if (!inA) - inA = true; - else { - inA = false; - iA++; - } - } - if (nextB == pos) { - if (!inB) - inB = true; - else { - inB = false; - iB++; - } - } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF } - return result; + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) } -// Given a number of fragments for the outer tree, and a set of ranges -// to parse, find fragments for inner trees mounted around those -// ranges, if any. -function enterFragments(mounts, ranges) { - let result = []; - for (let { pos, mount, frag } of mounts) { - let startPos = pos + (mount.overlay ? mount.overlay[0].from : 0), endPos = startPos + mount.tree.length; - let from = Math.max(frag.from, startPos), to = Math.min(frag.to, endPos); - if (mount.overlay) { - let overlay = mount.overlay.map(r => new Range(r.from + pos, r.to + pos)); - let changes = findCoverChanges(ranges, overlay, from, to); - for (let i = 0, pos = from;; i++) { - let last = i == changes.length, end = last ? to : changes[i].from; - if (end > pos) - result.push(new TreeFragment(pos, end, mount.tree, -startPos, frag.from >= pos, frag.to <= end)); - if (last) - break; - pos = changes[i].to; - } - } - else { - result.push(new TreeFragment(from, to, mount.tree, -startPos, frag.from >= startPos, frag.to <= endPos)); - } - } - return result; + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +var MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + var len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = '' + var i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res } -exports.DefaultBufferLength = DefaultBufferLength; -exports.MountedTree = MountedTree; -exports.NodeProp = NodeProp; -exports.NodeSet = NodeSet; -exports.NodeType = NodeType; -exports.Parser = Parser; -exports.Tree = Tree; -exports.TreeBuffer = TreeBuffer; -exports.TreeCursor = TreeCursor; -exports.TreeFragment = TreeFragment; -exports.parseMixed = parseMixed; +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) -},{}],56:[function(require,module,exports){ -'use strict'; + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} -Object.defineProperty(exports, '__esModule', { value: true }); +function latin1Slice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) -var lr = require('@lezer/lr'); -var common = require('@lezer/common'); + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} -// This file was generated by lezer-generator. You probably shouldn't edit it. -const noSemi = 279, - incdec = 1, - incdecPrefix = 2, - templateContent = 280, - InterpolationStart = 3, - templateEnd = 281, - insertSemi = 282, - TSExtends = 4, - spaces = 284, - newline = 285, - LineComment = 5, - BlockComment = 6, - Dialect_ts = 1; +function hexSlice (buf, start, end) { + var len = buf.length -/* Hand-written tokenizers for JavaScript tokens that can't be - expressed by lezer's built-in tokenizer. */ + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len -const space = [9, 10, 11, 12, 13, 32, 133, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, - 8201, 8202, 8232, 8233, 8239, 8287, 12288]; + var out = '' + for (var i = start; i < end; ++i) { + out += toHex(buf[i]) + } + return out +} -const braceR = 125, braceL = 123, semicolon = 59, slash = 47, star = 42, - plus = 43, minus = 45, dollar = 36, backtick = 96, backslash = 92; +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) + } + return res +} -const trackNewline = new lr.ContextTracker({ - start: false, - shift(context, term) { - return term == LineComment || term == BlockComment || term == spaces ? context : term == newline - }, - strict: false -}); +Buffer.prototype.slice = function slice (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end -const insertSemicolon = new lr.ExternalTokenizer((input, stack) => { - let {next} = input; - if ((next == braceR || next == -1 || stack.context) && stack.canShift(insertSemi)) - input.acceptToken(insertSemi); -}, {contextual: true, fallback: true}); + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } -const noSemicolon = new lr.ExternalTokenizer((input, stack) => { - let {next} = input, after; - if (space.indexOf(next) > -1) return - if (next == slash && ((after = input.peek(1)) == slash || after == star)) return - if (next != braceR && next != semicolon && next != -1 && !stack.context && stack.canShift(noSemi)) - input.acceptToken(noSemi); -}, {contextual: true}); + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } -const incdecToken = new lr.ExternalTokenizer((input, stack) => { - let {next} = input; - if (next == plus || next == minus) { - input.advance(); - if (next == input.next) { - input.advance(); - let mayPostfix = !stack.context && stack.canShift(incdec); - input.acceptToken(mayPostfix ? incdec : incdecPrefix); - } + if (end < start) end = start + + var newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + newBuf.__proto__ = Buffer.prototype + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul } -}, {contextual: true}); -const template = new lr.ExternalTokenizer(input => { - for (let afterDollar = false, i = 0;; i++) { - let {next} = input; - if (next < 0) { - if (i) input.acceptToken(templateContent); - break - } else if (next == backtick) { - if (i) input.acceptToken(templateContent); - else input.acceptToken(templateEnd, 1); - break - } else if (next == braceL && afterDollar) { - if (i == 1) input.acceptToken(InterpolationStart, 1); - else input.acceptToken(templateContent, -1); - break - } else if (next == 10 /* "\n" */ && i) { - // Break up template strings on lines, to avoid huge tokens - input.advance(); - input.acceptToken(templateContent); - break - } else if (next == backslash) { - input.advance(); - } - afterDollar = next == dollar; - input.advance(); + return val +} + +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) } -}); -function tsExtends(value, stack) { - return value == "extends" && stack.dialectEnabled(Dialect_ts) ? TSExtends : -1 + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val } -// This file was generated by lezer-generator. You probably shouldn't edit it. -const spec_identifier = {__proto__:null,export:18, as:23, from:29, default:32, async:37, function:38, this:48, true:56, false:56, void:66, typeof:70, null:86, super:88, new:122, await:139, yield:141, delete:142, class:152, extends:154, public:197, private:197, protected:197, readonly:199, instanceof:220, in:222, const:224, import:256, keyof:307, unique:311, infer:317, is:351, abstract:371, implements:373, type:375, let:378, var:380, interface:387, enum:391, namespace:397, module:399, declare:403, global:407, for:428, of:437, while:440, with:444, do:448, if:452, else:454, switch:458, case:464, try:470, catch:472, finally:474, return:478, throw:482, break:486, continue:490, debugger:494}; -const spec_word = {__proto__:null,async:109, get:111, set:113, public:161, private:161, protected:161, static:163, abstract:165, override:167, readonly:173, new:355}; -const spec_LessThan = {__proto__:null,"<":129}; -const parser = lr.LRParser.deserialize({ - version: 13, - states: "$1jO`QYOOO'QQ!LdO'#ChO'XOSO'#DVO)dQYO'#D]O)tQYO'#DhO){QYO'#DrO-xQYO'#DxOOQO'#E]'#E]O.]QWO'#E[O.bQWO'#E[OOQ!LS'#Ef'#EfO0aQ!LdO'#IrO2wQ!LdO'#IsO3eQWO'#EzO3jQpO'#FaOOQ!LS'#FS'#FSO3rO!bO'#FSO4QQWO'#FhO5_QWO'#FgOOQ!LS'#Is'#IsOOQ!LQ'#Ir'#IrOOQQ'#J['#J[O5dQWO'#HnO5iQ!LYO'#HoOOQQ'#If'#IfOOQQ'#Hp'#HpQ`QYOOO){QYO'#DjO5qQWO'#G[O5vQ#tO'#CmO6UQWO'#EZO6aQWO'#EgO6fQ#tO'#FRO7QQWO'#G[O7VQWO'#G`O7bQWO'#G`O7pQWO'#GcO7pQWO'#GdO7pQWO'#GfO5qQWO'#GiO8aQWO'#GlO9oQWO'#CdO:PQWO'#GyO:XQWO'#HPO:XQWO'#HRO`QYO'#HTO:XQWO'#HVO:XQWO'#HYO:^QWO'#H`O:cQ!LZO'#HdO){QYO'#HfO:nQ!LZO'#HhO:yQ!LZO'#HjO5iQ!LYO'#HlO){QYO'#DWOOOS'#Hr'#HrO;UOSO,59qOOQ!LS,59q,59qO=gQbO'#ChO=qQYO'#HsO>UQWO'#ItO@TQbO'#ItO'dQYO'#ItO@[QWO,59wO@rQ&jO'#DbOAkQWO'#E]OAxQWO'#JPOBTQWO'#JOOBTQWO'#JOOB]QWO,5:yOBbQWO'#I}OBiQWO'#DyO5vQ#tO'#EZOBwQWO'#EZOCSQ`O'#FROOQ!LS,5:S,5:SOC[QYO,5:SOEYQ!LdO,5:^OEvQWO,5:dOFaQ!LYO'#I|O7VQWO'#I{OFhQWO'#I{OFpQWO,5:xOFuQWO'#I{OGTQYO,5:vOITQWO'#EWOJ_QWO,5:vOKnQWO'#DlOKuQYO'#DqOLPQ&jO,5;PO){QYO,5;POOQQ'#Er'#ErOOQQ'#Et'#EtO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;RO){QYO,5;ROOQQ'#Ex'#ExOLXQYO,5;cOOQ!LS,5;h,5;hOOQ!LS,5;i,5;iONXQWO,5;iOOQ!LS,5;j,5;jO){QYO'#H}ON^Q!LYO,5YOOQQ'#Ii'#IiOOQQ,5>Z,5>ZOOQQ-E;n-E;nO!+YQ!LdO,5:UOOQ!LQ'#Cp'#CpO!+yQ#tO,5O,5>OO){QYO,5>OO5iQ!LYO,5>QOOQQ,5>S,5>SO!8VQWO,5>SOOQQ,5>U,5>UO!8VQWO,5>UOOQQ,5>W,5>WO!8[Q`O,59rOOOS-E;p-E;pOOQ!LS1G/]1G/]O!8aQbO,5>_O'dQYO,5>_OOQO,5>d,5>dO!8kQYO'#HsOOQO-E;q-E;qO!8xQWO,5?`O!9QQbO,5?`O!9XQWO,5?jOOQ!LS1G/c1G/cO!9aQpO'#DTOOQO'#Iv'#IvO){QYO'#IvO!:OQpO'#IvO!:mQpO'#DcO!;OQ&jO'#DcO!=ZQYO'#DcO!=bQWO'#IuO!=jQWO,59|O!=oQWO'#EaO!=}QWO'#JQO!>VQWO,5:zO!>mQ&jO'#DcO){QYO,5?kO!>wQWO'#HxOOQO-E;v-E;vO!9XQWO,5?jOOQ!LQ1G0e1G0eO!@TQ&jO'#D|OOQ!LS,5:e,5:eO){QYO,5:eOITQWO,5:eO!@[QWO,5:eO:^QWO,5:uO!,rQpO,5:uO!,zQ#tO,5:uO5vQ#tO,5:uOOQ!LS1G/n1G/nOOQ!LS1G0O1G0OOOQ!LQ'#EV'#EVO){QYO,5?hO!@gQ!LYO,5?hO!@xQ!LYO,5?hO!APQWO,5?gO!AXQWO'#HzO!APQWO,5?gOOQ!LQ1G0d1G0dO7VQWO,5?gOOQ!LS1G0b1G0bO!AsQ!LdO1G0bO!BdQ!LbO,5:rOOQ!LS'#Fq'#FqO!CQQ!LdO'#IoOGTQYO1G0bO!EPQ#tO'#IwO!EZQWO,5:WO!E`QbO'#IxO){QYO'#IxO!EjQWO,5:]OOQ!LS'#DT'#DTOOQ!LS1G0k1G0kO!EoQWO1G0kO!HQQ!LdO1G0mO!HXQ!LdO1G0mO!JlQ!LdO1G0mO!JsQ!LdO1G0mO!LzQ!LdO1G0mO!M_Q!LdO1G0mO#!OQ!LdO1G0mO#!VQ!LdO1G0mO#$jQ!LdO1G0mO#$qQ!LdO1G0mO#&fQ!LdO1G0mO#)`Q7^O'#ChO#+ZQ7^O1G0}O#-UQ7^O'#IsOOQ!LS1G1T1G1TO#-iQ!LdO,5>iOOQ!LQ-E;{-E;{O#.YQ!LdO1G0mOOQ!LS1G0m1G0mO#0[Q!LdO1G1QO#0{QpO,5;sO#1QQpO,5;tO#1VQpO'#F[O#1kQWO'#FZOOQO'#JU'#JUOOQO'#H{'#H{O#1pQpO1G1]OOQ!LS1G1]1G1]OOOO1G1f1G1fO#2OQ7^O'#IrO#2YQWO,5;}OLXQYO,5;}OOOO-E;z-E;zOOQ!LS1G1Y1G1YOOQ!LS,5VQ&jO'#GhOOQQ1G2l1G2lO!&wQ&jO'#IWO!0OQ`O1G2oOOQQ1G2o1G2oOOQQ,5=Y,5=YO#>_Q#tO,5=[O5qQWO,5=[O#5YQWO,5=_O5_QWO,5=_O!,rQpO,5=_O!,zQ#tO,5=_O5vQ#tO,5=_O#>pQWO'#J_O#>{QWO,5=`OOQQ1G.j1G.jO#?QQ!LYO1G.jO#?]QWO1G.jO#?bQWO1G.jO5iQ!LYO1G.jO#?jQbO,5?|O#?tQWO,5?|O#@PQYO,5=gO#@WQWO,5=gO7VQWO,5?|OOQQ1G3P1G3PO`QYO1G3POOQQ1G3V1G3VOOQQ1G3X1G3XO:XQWO1G3ZO#@]QYO1G3]O#DWQYO'#H[OOQQ1G3`1G3`O:^QWO1G3fO#DeQWO1G3fO5iQ!LYO1G3jOOQQ1G3l1G3lOOQ!LQ'#Fx'#FxO5iQ!LYO1G3nO5iQ!LYO1G3pOOOS1G/^1G/^O#DmQ`O,5_O#EPQWO1G4zO#EXQWO1G5UO#EaQWO,5?bOLXQYO,5:{O7VQWO,5:{O:^QWO,59}OLXQYO,59}O!,rQpO,59}O#EfQ7^O,59}OOQO,5:{,5:{O#EpQ&jO'#HtO#FWQWO,5?aOOQ!LS1G/h1G/hO#F`Q&jO'#HyO#FtQWO,5?lOOQ!LQ1G0f1G0fO!;OQ&jO,59}O#F|QbO1G5VO7VQWO,5>dOOQ!LQ'#ES'#ESO#GWQ!LrO'#ETO!?{Q&jO'#D}OOQO'#Hw'#HwO#GrQ&jO,5:hOOQ!LS,5:h,5:hO#GyQ&jO'#D}O#H[Q&jO'#D}O#HcQ&jO'#EYO#HfQ&jO'#ETO#HsQ&jO'#ETO!?{Q&jO'#ETO#IWQWO1G0PO#I]Q`O1G0POOQ!LS1G0P1G0PO){QYO1G0POITQWO1G0POOQ!LS1G0a1G0aO:^QWO1G0aO!,rQpO1G0aO!,zQ#tO1G0aO#IdQ!LdO1G5SO){QYO1G5SO#ItQ!LYO1G5SO#JVQWO1G5RO7VQWO,5>fOOQO,5>f,5>fO#J_QWO,5>fOOQO-E;x-E;xO#JVQWO1G5RO#JmQ!LdO,59jO#LlQ!LdO,5k,5>kO$(]QWO,5>kOOQ!LS1G2P1G2PP$(bQWO'#IPPOQ!LS-E;}-E;}O$)RQ#tO1G2[O$)tQ#tO1G2^O$*OQ#tO1G2`OOQ!LS1G1x1G1xO$*VQWO'#IOO$*eQWO,5?sO$*eQWO,5?sO$*mQWO,5?sO$*xQWO,5?sOOQO1G1z1G1zO$+WQ#tO1G1yO$+hQWO'#IQO$+xQWO,5?tOITQWO,5?tO$,QQ`O,5?tOOQ!LS1G1}1G1}O5iQ!LYO,5n,5>nOOQO-Ev,5>vOOQO-Ep,5>pOOQ!LQ-Er,5>rOOQO-E`,5>`OOQO-E;r-E;rOOQO,5>e,5>eOOQO-E;w-E;wO!,rQpO1G/iO:^QWO,5:iOOQO,5:o,5:oO){QYO,5:oO$9pQ!LYO,5:oO$9{Q!LYO,5:oO!,rQpO,5:iOOQO-E;u-E;uOOQ!LS1G0S1G0SO!?{Q&jO,5:iO$:ZQ&jO,5:iO$:lQ!LrO,5:oO$;WQ&jO,5:iO!?{Q&jO,5:oOOQO,5:t,5:tO$;_Q&jO,5:oO$;lQ!LYO,5:oOOQ!LS7+%k7+%kO#IWQWO7+%kO#I]Q`O7+%kOOQ!LS7+%{7+%{O:^QWO7+%{O!,rQpO7+%{O$lQ!LdO1G2^O$@nQ!LdO1G1yO$BvQ#tO,5>aOOQO-E;s-E;sO$CQQbO,5>bO){QYO,5>bOOQO-E;t-E;tO$C[QWO1G5OO$CdQ7^O1G0bO$EkQ7^O1G0mO$ErQ7^O1G0mO$GsQ7^O1G0mO$GzQ7^O1G0mO$IoQ7^O1G0mO$JSQ7^O1G0mO$LaQ7^O1G0mO$LhQ7^O1G0mO$NiQ7^O1G0mO$NpQ7^O1G0mO%!eQ7^O1G0mO%!xQ!LdO<iOOOO7+'T7+'TOOOS1G/R1G/ROOQ!LS1G4V1G4VOJdQWO7+'zO%'rQWO,5>jO5qQWO,5>jOOQO-E;|-E;|O%(QQWO1G5_O%(QQWO1G5_O%(YQWO1G5_O%(eQ`O,5>lO%(oQWO,5>lOITQWO,5>lOOQO-Eu,5>uO%,RQWO,5>uO%,WQWO,5>uOOQO-EtOOQO-ERQ#tO<cQWO1G4UO%>nQWO1G4UO%>|QWO7+*yO%>|QWO7+*yOITQWO1G4WO%?UQ`O1G4WO%?`QWO7+*zOOQO7+'o7+'oO5iQ!LYO7+'oOOQO7+'n7+'nO$,[QWO7+'pO%?hQ`O7+'pOOQO7+'t7+'tO5iQ!LYO7+'nO$,[QWO7+'oO%?oQWO7+'pOITQWO7+'pO#5TQWO7+'oO%?tQ#tO<oOOQO-EqOOQO-E{AN>{OOQOAN>uAN>uO%0}Q!LdOAN>{O:^QWOAN>uO){QYOAN>{O!,rQpOAN>uO&(PQ!LYOAN>{O&([Q7^O<^O!O&OO~Ox&RO!W&]O!X&UO!Y&UO'[$bO~O]&SOk&SO!Q&VO'e&PO!S'iP!S'tP~P@aO!O'qX!R'qX!]'qX!c'qX'n'qX~O!{'qX#W#PX!S'qX~PAYO!{&^O!O'sX!R'sX~O!R&_O!O'rX~O!O&bO~O!{#eO~PAYOS&fO!T&cO!o&eO'Z$`O~Oc&kO!d$XO'Z$`O~Ou$nO!d$mO~O!S&lO~P`Ou!{Ov!{Ox!|O!b!yO!d!zO'dQOP!faZ!faj!fa!R!fa!a!fa!j!fa#[!fa#]!fa#^!fa#_!fa#`!fa#a!fa#b!fa#c!fa#e!fa#g!fa#i!fa#j!fa'n!fa'u!fa'v!fa~O_!fa'U!fa!O!fa!c!fan!fa!T!fa%Q!fa!]!fa~PCcO!c&mO~O!]!wO!{&oO'n&nO!R'pX_'pX'U'pX~O!c'pX~PE{O!R&sO!c'oX~O!c&uO~Ox$tO!T$uO#V&vO'Z$`O~OPTOQTO]cOb!kOc!jOhcOjTOkcOlcOqTOsTOxRO{cO|cO}cO!TSO!_kO!dUO!gTO!hTO!iTO!jTO!kTO!n!iO#t!lO#x^O'Z9YO'dQO'mYO'zaO~O]#qOh$OOj#rOk#qOl#qOq$POs9lOx#xO!T#yO!_:oO!d#vO#V9rO#t$TO$_9nO$a9pO$d$UO'Z&zO'd#sO~O#W&|O~O]#qOh$OOj#rOk#qOl#qOq$POs$QOx#xO!T#yO!_$VO!d#vO#V$WO#t$TO$_$RO$a$SO$d$UO'Z&zO'd#sO~O'_'kP~PJdO!Q'QO!c'lP~P){O'e'SO'mYO~OP9VOQ9VO]cOb:mOc!jOhcOj9VOkcOlcOq9VOs9VOxRO{cO|cO}cO!T!bO!_9XO!dUO!g9VO!h9VO!i9VO!j9VO!k9VO!n!iO#t!lO#x^O'Z'bO'dQO'mYO'z:kO~O!d!zO~O!R#bO_$]a'U$]a!c$]a!O$]a!T$]a%Q$]a!]$]a~O#d'iO~PITO!]'kO!T'wX#w'wX#z'wX$R'wX~Ou'lO~P! POu'lO!T'wX#w'wX#z'wX$R'wX~O!T'nO#w'rO#z'mO$R'sO~O!Q'vO~PLXO#z#fO$R'yO~Ou$eXx$eX!b$eX'n$eX'u$eX'v$eX~OSfX!RfX!{fX'_fX'_$eX~P!!iOk'{O~OR'|O'S'}O'T(PO~Ou(ROx(SO'n#[O'u(UO'v(WO~O'_(QO~P!#rO'_(ZO~O]#qOh$OOj#rOk#qOl#qOq$POs9lOx#xO!T#yO!_:oO!d#vO#V9rO#t$TO$_9nO$a9pO$d$UO'd#sO~O!Q(_O'Z([O!c'{P~P!$aO#W(aO~O!Q(eO'Z(bO!O'|P~P!$aO_(nOj(sOx(kO!W(qO!X(jO!Y(jO!d(hO!x(rO$w(mO'[$bO'e(gO~O!S(pO~P!&XO!b!yOu'cXx'cX'n'cX'u'cX'v'cX!R'cX!{'cX~O'_'cX#m'cX~P!'TOS(vO!{(uO!R'bX'_'bX~O!R(wO'_'aX~O'Z(yO~O!d)OO~O'Z&zO~O!d(hO~Ox$tO!Q!rO!T$uO#U!uO#V!rO'Z$`O!c'oP~O!]!wO#W)SO~OP#^OZ#dOj#ROu!{Ov!{Ox!|O!a#TO!b!yO!d!zO!j#^O#[#PO#]#QO#^#QO#_#QO#`#SO#a#TO#b#TO#c#TO#e#UO#g#WO#i#YO#j#ZO'dQO'n#[O'u!}O'v#OO~O_!^a!R!^a'U!^a!O!^a!c!^an!^a!T!^a%Q!^a!]!^a~P!)fOS)[O!T&cO!o)ZO%Q)YO'`$cO~O'Z$zO'_'aP~O!])_O!T'^X_'^X'U'^X~O!d$XO'`$cO~O!d$XO'Z$`O'`$cO~O!]!wO#W&|O~O])jO%R)kO'Z)gO!S(TP~O!R)lO^(SX~O'e'SO~OZ)pO~O^)qO~O!T$kO'Z$`O'[$bO^(SP~Ox$tO!Q)vO!R&_O!T$uO'Z$`O!O'rP~O]&YOk&YO!Q)wO'e'SO!S'tP~O!R)xO_(PX'U(PX~O!{)|O'`$cO~OS*PO!T#yO'`$cO~O!T*RO~Ou*TO!TSO~O!n*YO~Oc*_O~O'Z(yO!S(RP~Oc$iO~O%RtO'Z$zO~P8tOZ*eO^*dO~OPTOQTO]cObnOcmOhcOjTOkcOlcOqTOsTOxRO{cO|cO}cO!_kO!dUO!gTO!hTO!iTO!jTO!kTO!nlO#x^O%PqO'dQO'mYO'zaO~O!T!bO#t!lO'Z9YO~P!1RO^*dO_$[O'U$[O~O_*iO#d*kO%T*kO%U*kO~P){O!d%_O~O%t*pO~O!T*rO~O&U*uO&V*tOP&SaQ&SaX&Sa]&Sa_&Sab&Sac&Sah&Saj&Sak&Sal&Saq&Sas&Sax&Sa{&Sa|&Sa}&Sa!T&Sa!_&Sa!d&Sa!g&Sa!h&Sa!i&Sa!j&Sa!k&Sa!n&Sa#d&Sa#t&Sa#x&Sa%P&Sa%R&Sa%T&Sa%U&Sa%X&Sa%Z&Sa%^&Sa%_&Sa%a&Sa%n&Sa%t&Sa%v&Sa%x&Sa%z&Sa%}&Sa&T&Sa&X&Sa&Z&Sa&]&Sa&_&Sa&a&Sa'Q&Sa'Z&Sa'd&Sa'm&Sa'z&Sa!S&Sa%{&Sa`&Sa&Q&Sa~O'Z*xO~On*{O~O!O&ga!R&ga~P!)fO!Q+PO!O&gX!R&gX~P){O!R%yO!O'ha~O!O'ha~P>^O!R&_O!O'ra~O!RwX!R!ZX!SwX!S!ZX!]wX!]!ZX!d!ZX!{wX'`!ZX~O!]+UO!{+TO!R#TX!R'jX!S#TX!S'jX!]'jX!d'jX'`'jX~O!]+WO!d$XO'`$cO!R!VX!S!VX~O]&QOk&QOx&RO'e(gO~OP9VOQ9VO]cOb:mOc!jOhcOj9VOkcOlcOq9VOs9VOxRO{cO|cO}cO!T!bO!_9XO!dUO!g9VO!h9VO!i9VO!j9VO!k9VO!n!iO#t!lO#x^O'dQO'mYO'z:kO~O'Z9vO~P!;^O!R+[O!S'iX~O!S+^O~O!]+UO!{+TO!R#TX!S#TX~O!R+_O!S'tX~O!S+aO~O]&QOk&QOx&RO'[$bO'e(gO~O!X+bO!Y+bO~P!>[Ox$tO!Q+dO!T$uO'Z$`O!O&lX!R&lX~O_+hO!W+kO!X+gO!Y+gO!r+oO!s+mO!t+nO!u+lO!x+pO'[$bO'e(gO'm+eO~O!S+jO~P!?]OS+uO!T&cO!o+tO~O!{+{O!R'pa!c'pa_'pa'U'pa~O!]!wO~P!@gO!R&sO!c'oa~Ox$tO!Q,OO!T$uO#U,QO#V,OO'Z$`O!R&nX!c&nX~O_#Oi!R#Oi'U#Oi!O#Oi!c#Oin#Oi!T#Oi%Q#Oi!]#Oi~P!)fO#W!za!R!za!c!za!{!za!T!za_!za'U!za!O!za~P!#rO#W'cXP'cXZ'cX_'cXj'cXv'cX!a'cX!d'cX!j'cX#['cX#]'cX#^'cX#_'cX#`'cX#a'cX#b'cX#c'cX#e'cX#g'cX#i'cX#j'cX'U'cX'd'cX!c'cX!O'cX!T'cXn'cX%Q'cX!]'cX~P!'TO!R,ZO'_'kX~P!#rO'_,]O~O!R,^O!c'lX~P!)fO!c,aO~O!O,bO~OP#^Ou!{Ov!{Ox!|O!b!yO!d!zO!j#^O'dQOZ#Zi_#Zij#Zi!R#Zi!a#Zi#]#Zi#^#Zi#_#Zi#`#Zi#a#Zi#b#Zi#c#Zi#e#Zi#g#Zi#i#Zi#j#Zi'U#Zi'n#Zi'u#Zi'v#Zi!O#Zi!c#Zin#Zi!T#Zi%Q#Zi!]#Zi~O#[#Zi~P!EtO#[#PO~P!EtOP#^Ou!{Ov!{Ox!|O!b!yO!d!zO!j#^O#[#PO#]#QO#^#QO#_#QO'dQOZ#Zi_#Zi!R#Zi!a#Zi#`#Zi#a#Zi#b#Zi#c#Zi#e#Zi#g#Zi#i#Zi#j#Zi'U#Zi'n#Zi'u#Zi'v#Zi!O#Zi!c#Zin#Zi!T#Zi%Q#Zi!]#Zi~Oj#Zi~P!H`Oj#RO~P!H`OP#^Oj#ROu!{Ov!{Ox!|O!b!yO!d!zO!j#^O#[#PO#]#QO#^#QO#_#QO#`#SO'dQO_#Zi!R#Zi#e#Zi#g#Zi#i#Zi#j#Zi'U#Zi'n#Zi'u#Zi'v#Zi!O#Zi!c#Zin#Zi!T#Zi%Q#Zi!]#Zi~OZ#Zi!a#Zi#a#Zi#b#Zi#c#Zi~P!JzOZ#dO!a#TO#a#TO#b#TO#c#TO~P!JzOP#^OZ#dOj#ROu!{Ov!{Ox!|O!a#TO!b!yO!d!zO!j#^O#[#PO#]#QO#^#QO#_#QO#`#SO#a#TO#b#TO#c#TO#e#UO'dQO_#Zi!R#Zi#g#Zi#i#Zi#j#Zi'U#Zi'n#Zi'v#Zi!O#Zi!c#Zin#Zi!T#Zi%Q#Zi!]#Zi~O'u#Zi~P!MrO'u!}O~P!MrOP#^OZ#dOj#ROu!{Ov!{Ox!|O!a#TO!b!yO!d!zO!j#^O#[#PO#]#QO#^#QO#_#QO#`#SO#a#TO#b#TO#c#TO#e#UO#g#WO'dQO'u!}O_#Zi!R#Zi#i#Zi#j#Zi'U#Zi'n#Zi!O#Zi!c#Zin#Zi!T#Zi%Q#Zi!]#Zi~O'v#Zi~P#!^O'v#OO~P#!^OP#^OZ#dOj#ROu!{Ov!{Ox!|O!a#TO!b!yO!d!zO!j#^O#[#PO#]#QO#^#QO#_#QO#`#SO#a#TO#b#TO#c#TO#e#UO#g#WO#i#YO'dQO'u!}O'v#OO~O_#Zi!R#Zi#j#Zi'U#Zi'n#Zi!O#Zi!c#Zin#Zi!T#Zi%Q#Zi!]#Zi~P#$xOP[XZ[Xj[Xu[Xv[Xx[X!a[X!b[X!d[X!j[X!{[X#WdX#[[X#][X#^[X#_[X#`[X#a[X#b[X#c[X#e[X#g[X#i[X#j[X#o[X'd[X'n[X'u[X'v[X!R[X!S[X~O#m[X~P#']OP#^OZ9jOj9_Ou!{Ov!{Ox!|O!a9aO!b!yO!d!zO!j#^O#[9]O#]9^O#^9^O#_9^O#`9`O#a9aO#b9aO#c9aO#e9bO#g9dO#i9fO#j9gO'dQO'n#[O'u!}O'v#OO~O#m,dO~P#)gOP'gXZ'gXj'gXu'gXv'gXx'gX!a'gX!b'gX!d'gX!j'gX#['gX#]'gX#^'gX#_'gX#`'gX#a'gX#b'gX#e'gX#g'gX#i'gX#j'gX'd'gX'n'gX'u'gX'v'gX!R'gX~O!{9kO#o9kO#c'gX#m'gX!S'gX~P#+bO_&qa!R&qa'U&qa!c&qan&qa!O&qa!T&qa%Q&qa!]&qa~P!)fOP#ZiZ#Zi_#Zij#Ziv#Zi!R#Zi!a#Zi!b#Zi!d#Zi!j#Zi#[#Zi#]#Zi#^#Zi#_#Zi#`#Zi#a#Zi#b#Zi#c#Zi#e#Zi#g#Zi#i#Zi#j#Zi'U#Zi'd#Zi!O#Zi!c#Zin#Zi!T#Zi%Q#Zi!]#Zi~P!#rO_#ni!R#ni'U#ni!O#ni!c#nin#ni!T#ni%Q#ni!]#ni~P!)fO#z,fO~O#z,gO~O!]'kO!{,hO!T$OX#w$OX#z$OX$R$OX~O!Q,iO~O!T'nO#w,kO#z'mO$R,lO~O!R9hO!S'fX~P#)gO!S,mO~O$R,oO~OR'|O'S'}O'T,rO~O],uOk,uO!O,vO~O!RdX!]dX!cdX!c$eX'ndX~P!!iO!c,|O~P!#rO!R,}O!]!wO'n&nO!c'{X~O!c-SO~O!O$eX!R$eX!]$lX~P!!iO!R-UO!O'|X~P!#rO!]-WO~O!O-YO~O!Q(_O'Z$`O!c'{P~Oj-^O!]!wO!d$XO'`$cO'n&nO~O!])_O~O!S-dO~P!&XO!X-eO!Y-eO'[$bO'e(gO~Ox-gO'e(gO~O!x-hO~O'Z$zO!R&vX'_&vX~O!R(wO'_'aa~Ou-mOv-mOx-nO'nra'ura'vra!Rra!{ra~O'_ra#mra~P#6fOu(ROx(SO'n$^a'u$^a'v$^a!R$^a!{$^a~O'_$^a#m$^a~P#7[Ou(ROx(SO'n$`a'u$`a'v$`a!R$`a!{$`a~O'_$`a#m$`a~P#7}O]-oO~O#W-pO~O'_$na!R$na#m$na!{$na~P!#rO#W-sO~OS-|O!T&cO!o-{O%Q-zO~O'_-}O~O]#qOj#rOk#qOl#qOq$POs9lOx#xO!T#yO!_:oO!d#vO#V9rO#t$TO$_9nO$a9pO$d$UO'd#sO~Oh.PO'Z.OO~P#9tO!])_O!T'^a_'^a'U'^a~O#W.VO~OZ[X!RdX!SdX~O!R.WO!S(TX~O!S.YO~OZ.ZO~O].]O'Z)gO~O!T$kO'Z$`O^'OX!R'OX~O!R)lO^(Sa~O!c.`O~P!)fO].bO~OZ.cO~O^.dO~OS-|O!T&cO!o-{O%Q-zO'`$cO~O!R)xO_(Pa'U(Pa~O!{.jO~OS.mO!T#yO~O'e'SO!S(QP~OS.wO!T.sO!o.vO%Q.uO'`$cO~OZ/RO!R/PO!S(RX~O!S/SO~O^/UO_$[O'U$[O~O]/VO~O]/WO'Z(yO~O#c/XO%r/YO~P0zO!{#eO#c/XO%r/YO~O_/ZO~P){O_/]O~O%{/aOP%yiQ%yiX%yi]%yi_%yib%yic%yih%yij%yik%yil%yiq%yis%yix%yi{%yi|%yi}%yi!T%yi!_%yi!d%yi!g%yi!h%yi!i%yi!j%yi!k%yi!n%yi#d%yi#t%yi#x%yi%P%yi%R%yi%T%yi%U%yi%X%yi%Z%yi%^%yi%_%yi%a%yi%n%yi%t%yi%v%yi%x%yi%z%yi%}%yi&T%yi&X%yi&Z%yi&]%yi&_%yi&a%yi'Q%yi'Z%yi'd%yi'm%yi'z%yi!S%yi`%yi&Q%yi~O`/gO!S/eO&Q/fO~P`O!TSO!d/jO~O!R#bOn$]a~O!O&gi!R&gi~P!)fO!R%yO!O'hi~O!R&_O!O'ri~O!O/nO~O!R!Va!S!Va~P#)gO]&QOk&QO!Q/tO'e(gO!R&hX!S&hX~P@aO!R+[O!S'ia~O]&YOk&YO!Q)wO'e'SO!R&mX!S&mX~O!R+_O!S'ta~O!O'si!R'si~P!)fO_$[O!]!wO!d$XO!j0OO!{/|O'U$[O'`$cO'n&nO~O!S0RO~P!?]O!X0SO!Y0SO'[$bO'e(gO'm+eO~O!W0TO~P#GyO!TSO!W0TO!u0VO!x0WO~P#GyO!W0TO!s0YO!t0YO!u0VO!x0WO~P#GyO!T&cO~O!T&cO~P!#rO!R'pi!c'pi_'pi'U'pi~P!)fO!{0cO!R'pi!c'pi_'pi'U'pi~O!R&sO!c'oi~Ox$tO!T$uO#V0eO'Z$`O~O#WraPraZra_rajra!ara!bra!dra!jra#[ra#]ra#^ra#_ra#`ra#ara#bra#cra#era#gra#ira#jra'Ura'dra!cra!Ora!Tranra%Qra!]ra~P#6fO#W$^aP$^aZ$^a_$^aj$^av$^a!a$^a!b$^a!d$^a!j$^a#[$^a#]$^a#^$^a#_$^a#`$^a#a$^a#b$^a#c$^a#e$^a#g$^a#i$^a#j$^a'U$^a'd$^a!c$^a!O$^a!T$^an$^a%Q$^a!]$^a~P#7[O#W$`aP$`aZ$`a_$`aj$`av$`a!a$`a!b$`a!d$`a!j$`a#[$`a#]$`a#^$`a#_$`a#`$`a#a$`a#b$`a#c$`a#e$`a#g$`a#i$`a#j$`a'U$`a'd$`a!c$`a!O$`a!T$`an$`a%Q$`a!]$`a~P#7}O#W$naP$naZ$na_$naj$nav$na!R$na!a$na!b$na!d$na!j$na#[$na#]$na#^$na#_$na#`$na#a$na#b$na#c$na#e$na#g$na#i$na#j$na'U$na'd$na!c$na!O$na!T$na!{$nan$na%Q$na!]$na~P!#rO_#Oq!R#Oq'U#Oq!O#Oq!c#Oqn#Oq!T#Oq%Q#Oq!]#Oq~P!)fO!R&iX'_&iX~PJdO!R,ZO'_'ka~O!Q0mO!R&jX!c&jX~P){O!R,^O!c'la~O!R,^O!c'la~P!)fO#m!fa!S!fa~PCcO#m!^a!R!^a!S!^a~P#)gO!T1QO#x^O$P1RO~O!S1VO~On1WO~P!#rO_$Yq!R$Yq'U$Yq!O$Yq!c$Yqn$Yq!T$Yq%Q$Yq!]$Yq~P!)fO!O1XO~O],uOk,uO~Ou(ROx(SO'v(WO'n$xi'u$xi!R$xi!{$xi~O'_$xi#m$xi~P$(jOu(ROx(SO'n$zi'u$zi'v$zi!R$zi!{$zi~O'_$zi#m$zi~P$)]O#m1YO~P!#rO!Q1[O'Z$`O!R&rX!c&rX~O!R,}O!c'{a~O!R,}O!]!wO!c'{a~O!R,}O!]!wO'n&nO!c'{a~O'_$gi!R$gi#m$gi!{$gi~P!#rO!Q1cO'Z(bO!O&tX!R&tX~P!$aO!R-UO!O'|a~O!R-UO!O'|a~P!#rO!]!wO~O!]!wO#c1mO~Oj1qO!]!wO'n&nO~O!R'bi'_'bi~P!#rO!{1tO!R'bi'_'bi~P!#rO!c1wO~O_$Zq!R$Zq'U$Zq!O$Zq!c$Zqn$Zq!T$Zq%Q$Zq!]$Zq~P!)fO!R1{O!T'}X~P!#rO!T&cO%Q2OO~O!T&cO%Q2OO~P!#rO!T$eX$u[X_$eX'U$eX~P!!iO$u2SOugXxgX!TgX'ngX'ugX'vgX_gX'UgX~O$u2SO~O]2YO%R2ZO'Z)gO!R&}X!S&}X~O!R.WO!S(Ta~OZ2_O~O^2`O~O]2cO~OS2eO!T&cO!o2dO%Q2OO~O_$[O'U$[O~P!#rO!T#yO~P!#rO!R2jO!{2lO!S(QX~O!S2mO~Ox(kO!W2vO!X2oO!Y2oO!r2uO!s2tO!t2tO!x2sO'[$bO'e(gO'm+eO~O!S2rO~P$1nOS2}O!T.sO!o2|O%Q2{O~OS2}O!T.sO!o2|O%Q2{O'`$cO~O'Z(yO!R&|X!S&|X~O!R/PO!S(Ra~O]3XO'e3WO~O]3YO~O^3[O~O!c3_O~P){O_3aO~O_3aO~P){O#c3cO%r3dO~PE{O`/gO!S3hO&Q/fO~P`O!]3jO~O&V3kOP&SqQ&SqX&Sq]&Sq_&Sqb&Sqc&Sqh&Sqj&Sqk&Sql&Sqq&Sqs&Sqx&Sq{&Sq|&Sq}&Sq!T&Sq!_&Sq!d&Sq!g&Sq!h&Sq!i&Sq!j&Sq!k&Sq!n&Sq#d&Sq#t&Sq#x&Sq%P&Sq%R&Sq%T&Sq%U&Sq%X&Sq%Z&Sq%^&Sq%_&Sq%a&Sq%n&Sq%t&Sq%v&Sq%x&Sq%z&Sq%}&Sq&T&Sq&X&Sq&Z&Sq&]&Sq&_&Sq&a&Sq'Q&Sq'Z&Sq'd&Sq'm&Sq'z&Sq!S&Sq%{&Sq`&Sq&Q&Sq~O!R#Ti!S#Ti~P#)gO!{3mO!R#Ti!S#Ti~O!R!Vi!S!Vi~P#)gO_$[O!{3tO'U$[O~O_$[O!]!wO!{3tO'U$[O~O!X3xO!Y3xO'[$bO'e(gO'm+eO~O_$[O!]!wO!d$XO!j3yO!{3tO'U$[O'`$cO'n&nO~O!W3zO~P$:ZO!W3zO!u3}O!x4OO~P$:ZO_$[O!]!wO!j3yO!{3tO'U$[O'n&nO~O!R'pq!c'pq_'pq'U'pq~P!)fO!R&sO!c'oq~O#W$xiP$xiZ$xi_$xij$xiv$xi!a$xi!b$xi!d$xi!j$xi#[$xi#]$xi#^$xi#_$xi#`$xi#a$xi#b$xi#c$xi#e$xi#g$xi#i$xi#j$xi'U$xi'd$xi!c$xi!O$xi!T$xin$xi%Q$xi!]$xi~P$(jO#W$ziP$ziZ$zi_$zij$ziv$zi!a$zi!b$zi!d$zi!j$zi#[$zi#]$zi#^$zi#_$zi#`$zi#a$zi#b$zi#c$zi#e$zi#g$zi#i$zi#j$zi'U$zi'd$zi!c$zi!O$zi!T$zin$zi%Q$zi!]$zi~P$)]O#W$giP$giZ$gi_$gij$giv$gi!R$gi!a$gi!b$gi!d$gi!j$gi#[$gi#]$gi#^$gi#_$gi#`$gi#a$gi#b$gi#c$gi#e$gi#g$gi#i$gi#j$gi'U$gi'd$gi!c$gi!O$gi!T$gi!{$gin$gi%Q$gi!]$gi~P!#rO!R&ia'_&ia~P!#rO!R&ja!c&ja~P!)fO!R,^O!c'li~O#m#Oi!R#Oi!S#Oi~P#)gOP#^Ou!{Ov!{Ox!|O!b!yO!d!zO!j#^O'dQOZ#Zij#Zi!a#Zi#]#Zi#^#Zi#_#Zi#`#Zi#a#Zi#b#Zi#c#Zi#e#Zi#g#Zi#i#Zi#j#Zi#m#Zi'n#Zi'u#Zi'v#Zi!R#Zi!S#Zi~O#[#Zi~P$CqO#[9]O~P$CqOP#^Ou!{Ov!{Ox!|O!b!yO!d!zO!j#^O#[9]O#]9^O#^9^O#_9^O'dQOZ#Zi!a#Zi#`#Zi#a#Zi#b#Zi#c#Zi#e#Zi#g#Zi#i#Zi#j#Zi#m#Zi'n#Zi'u#Zi'v#Zi!R#Zi!S#Zi~Oj#Zi~P$EyOj9_O~P$EyOP#^Oj9_Ou!{Ov!{Ox!|O!b!yO!d!zO!j#^O#[9]O#]9^O#^9^O#_9^O#`9`O'dQO#e#Zi#g#Zi#i#Zi#j#Zi#m#Zi'n#Zi'u#Zi'v#Zi!R#Zi!S#Zi~OZ#Zi!a#Zi#a#Zi#b#Zi#c#Zi~P$HROZ9jO!a9aO#a9aO#b9aO#c9aO~P$HROP#^OZ9jOj9_Ou!{Ov!{Ox!|O!a9aO!b!yO!d!zO!j#^O#[9]O#]9^O#^9^O#_9^O#`9`O#a9aO#b9aO#c9aO#e9bO'dQO#g#Zi#i#Zi#j#Zi#m#Zi'n#Zi'v#Zi!R#Zi!S#Zi~O'u#Zi~P$JgO'u!}O~P$JgOP#^OZ9jOj9_Ou!{Ov!{Ox!|O!a9aO!b!yO!d!zO!j#^O#[9]O#]9^O#^9^O#_9^O#`9`O#a9aO#b9aO#c9aO#e9bO#g9dO'dQO'u!}O#i#Zi#j#Zi#m#Zi'n#Zi!R#Zi!S#Zi~O'v#Zi~P$LoO'v#OO~P$LoOP#^OZ9jOj9_Ou!{Ov!{Ox!|O!a9aO!b!yO!d!zO!j#^O#[9]O#]9^O#^9^O#_9^O#`9`O#a9aO#b9aO#c9aO#e9bO#g9dO#i9fO'dQO'u!}O'v#OO~O#j#Zi#m#Zi'n#Zi!R#Zi!S#Zi~P$NwO_#ky!R#ky'U#ky!O#ky!c#kyn#ky!T#ky%Q#ky!]#ky~P!)fOP#ZiZ#Zij#Ziv#Zi!a#Zi!b#Zi!d#Zi!j#Zi#[#Zi#]#Zi#^#Zi#_#Zi#`#Zi#a#Zi#b#Zi#c#Zi#e#Zi#g#Zi#i#Zi#j#Zi#m#Zi'd#Zi!R#Zi!S#Zi~P!#rO!b!yOP'cXZ'cXj'cXu'cXv'cXx'cX!a'cX!d'cX!j'cX#['cX#]'cX#^'cX#_'cX#`'cX#a'cX#b'cX#c'cX#e'cX#g'cX#i'cX#j'cX#m'cX'd'cX'n'cX'u'cX'v'cX!R'cX!S'cX~O#m#ni!R#ni!S#ni~P#)gO!S4`O~O!R&qa!S&qa~P#)gO!]!wO'n&nO!R&ra!c&ra~O!R,}O!c'{i~O!R,}O!]!wO!c'{i~O!O&ta!R&ta~P!#rO!]4gO~O!R-UO!O'|i~P!#rO!R-UO!O'|i~O!O4mO~O!]!wO#c4sO~Oj4tO!]!wO'n&nO~O!O4vO~O'_$iq!R$iq#m$iq!{$iq~P!#rO_$Zy!R$Zy'U$Zy!O$Zy!c$Zyn$Zy!T$Zy%Q$Zy!]$Zy~P!)fO!R1{O!T'}a~O!T&cO%Q4{O~O!T&cO%Q4{O~P!#rO_#Oy!R#Oy'U#Oy!O#Oy!c#Oyn#Oy!T#Oy%Q#Oy!]#Oy~P!)fOZ5OO~O]5QO'Z)gO~O!R.WO!S(Ti~O]5TO~O^5UO~O'e'SO!R&yX!S&yX~O!R2jO!S(Qa~O!S5cO~P$1nOx-gO'e(gO'm+eO~O!W5fO!X5eO!Y5eO!x0WO'[$bO'e(gO'm+eO~O!s5gO!t5gO~P%-iO!X5eO!Y5eO'[$bO'e(gO'm+eO~O!T.sO~O!T.sO%Q5iO~O!T.sO%Q5iO~P!#rOS5nO!T.sO!o5mO%Q5iO~OZ5sO!R&|a!S&|a~O!R/PO!S(Ri~O]5vO~O!c5wO~O!c5xO~O!c5yO~O!c5yO~P){O_5{O~O!]6OO~O!c6QO~O!R'si!S'si~P#)gO_$[O'U$[O~P!)fO_$[O!{6VO'U$[O~O_$[O!]!wO!{6VO'U$[O~O!X6[O!Y6[O'[$bO'e(gO'm+eO~O_$[O!]!wO!j6]O!{6VO'U$[O'n&nO~O!d$XO'`$cO~P%2TO!W6^O~P%1rO!R'py!c'py_'py'U'py~P!)fO#W$iqP$iqZ$iq_$iqj$iqv$iq!R$iq!a$iq!b$iq!d$iq!j$iq#[$iq#]$iq#^$iq#_$iq#`$iq#a$iq#b$iq#c$iq#e$iq#g$iq#i$iq#j$iq'U$iq'd$iq!c$iq!O$iq!T$iq!{$iqn$iq%Q$iq!]$iq~P!#rO!R&ji!c&ji~P!)fO#m#Oq!R#Oq!S#Oq~P#)gOu-mOv-mOx-nOPraZrajra!ara!bra!dra!jra#[ra#]ra#^ra#_ra#`ra#ara#bra#cra#era#gra#ira#jra#mra'dra'nra'ura'vra!Rra!Sra~Ou(ROx(SOP$^aZ$^aj$^av$^a!a$^a!b$^a!d$^a!j$^a#[$^a#]$^a#^$^a#_$^a#`$^a#a$^a#b$^a#c$^a#e$^a#g$^a#i$^a#j$^a#m$^a'd$^a'n$^a'u$^a'v$^a!R$^a!S$^a~Ou(ROx(SOP$`aZ$`aj$`av$`a!a$`a!b$`a!d$`a!j$`a#[$`a#]$`a#^$`a#_$`a#`$`a#a$`a#b$`a#c$`a#e$`a#g$`a#i$`a#j$`a#m$`a'd$`a'n$`a'u$`a'v$`a!R$`a!S$`a~OP$naZ$naj$nav$na!a$na!b$na!d$na!j$na#[$na#]$na#^$na#_$na#`$na#a$na#b$na#c$na#e$na#g$na#i$na#j$na#m$na'd$na!R$na!S$na~P!#rO#m$Yq!R$Yq!S$Yq~P#)gO#m$Zq!R$Zq!S$Zq~P#)gO!S6hO~O'_$|y!R$|y#m$|y!{$|y~P!#rO!]!wO!R&ri!c&ri~O!]!wO'n&nO!R&ri!c&ri~O!R,}O!c'{q~O!O&ti!R&ti~P!#rO!R-UO!O'|q~O!O6oO~P!#rO!O6oO~O!R'by'_'by~P!#rO!R&wa!T&wa~P!#rO!T$tq_$tq'U$tq~P!#rOZ6wO~O!R.WO!S(Tq~O]6zO~O!T&cO%Q6{O~O!T&cO%Q6{O~P!#rO!{6|O!R&ya!S&ya~O!R2jO!S(Qi~P#)gO!X7SO!Y7SO'[$bO'e(gO'm+eO~O!W7UO!x4OO~P%ArO!T.sO%Q7XO~O!T.sO%Q7XO~P!#rO]7`O'e7_O~O!R/PO!S(Rq~O!c7bO~O!c7bO~P){O!c7dO~O!c7eO~O!R#Ty!S#Ty~P#)gO_$[O!{7kO'U$[O~O_$[O!]!wO!{7kO'U$[O~O!X7nO!Y7nO'[$bO'e(gO'm+eO~O_$[O!]!wO!j7oO!{7kO'U$[O'n&nO~O#W$|yP$|yZ$|y_$|yj$|yv$|y!R$|y!a$|y!b$|y!d$|y!j$|y#[$|y#]$|y#^$|y#_$|y#`$|y#a$|y#b$|y#c$|y#e$|y#g$|y#i$|y#j$|y'U$|y'd$|y!c$|y!O$|y!T$|y!{$|yn$|y%Q$|y!]$|y~P!#rO#m#ky!R#ky!S#ky~P#)gOP$giZ$gij$giv$gi!a$gi!b$gi!d$gi!j$gi#[$gi#]$gi#^$gi#_$gi#`$gi#a$gi#b$gi#c$gi#e$gi#g$gi#i$gi#j$gi#m$gi'd$gi!R$gi!S$gi~P!#rOu(ROx(SO'v(WOP$xiZ$xij$xiv$xi!a$xi!b$xi!d$xi!j$xi#[$xi#]$xi#^$xi#_$xi#`$xi#a$xi#b$xi#c$xi#e$xi#g$xi#i$xi#j$xi#m$xi'd$xi'n$xi'u$xi!R$xi!S$xi~Ou(ROx(SOP$ziZ$zij$ziv$zi!a$zi!b$zi!d$zi!j$zi#[$zi#]$zi#^$zi#_$zi#`$zi#a$zi#b$zi#c$zi#e$zi#g$zi#i$zi#j$zi#m$zi'd$zi'n$zi'u$zi'v$zi!R$zi!S$zi~O#m$Zy!R$Zy!S$Zy~P#)gO#m#Oy!R#Oy!S#Oy~P#)gO!]!wO!R&rq!c&rq~O!R,}O!c'{y~O!O&tq!R&tq~P!#rO!O7uO~P!#rO!R.WO!S(Ty~O!R2jO!S(Qq~O!X8RO!Y8RO'[$bO'e(gO'm+eO~O!T.sO%Q8UO~O!T.sO%Q8UO~P!#rO!c8XO~O&V8YOP&S!ZQ&S!ZX&S!Z]&S!Z_&S!Zb&S!Zc&S!Zh&S!Zj&S!Zk&S!Zl&S!Zq&S!Zs&S!Zx&S!Z{&S!Z|&S!Z}&S!Z!T&S!Z!_&S!Z!d&S!Z!g&S!Z!h&S!Z!i&S!Z!j&S!Z!k&S!Z!n&S!Z#d&S!Z#t&S!Z#x&S!Z%P&S!Z%R&S!Z%T&S!Z%U&S!Z%X&S!Z%Z&S!Z%^&S!Z%_&S!Z%a&S!Z%n&S!Z%t&S!Z%v&S!Z%x&S!Z%z&S!Z%}&S!Z&T&S!Z&X&S!Z&Z&S!Z&]&S!Z&_&S!Z&a&S!Z'Q&S!Z'Z&S!Z'd&S!Z'm&S!Z'z&S!Z!S&S!Z%{&S!Z`&S!Z&Q&S!Z~O_$[O!{8_O'U$[O~O_$[O!]!wO!{8_O'U$[O~OP$iqZ$iqj$iqv$iq!a$iq!b$iq!d$iq!j$iq#[$iq#]$iq#^$iq#_$iq#`$iq#a$iq#b$iq#c$iq#e$iq#g$iq#i$iq#j$iq#m$iq'd$iq!R$iq!S$iq~P!#rO!R&yq!S&yq~P#)gO_$[O!{8tO'U$[O~OP$|yZ$|yj$|yv$|y!a$|y!b$|y!d$|y!j$|y#[$|y#]$|y#^$|y#_$|y#`$|y#a$|y#b$|y#c$|y#e$|y#g$|y#i$|y#j$|y#m$|y'd$|y!R$|y!S$|y~P!#rOn'fX~P.jOn[X!O[X!c[X%r[X!T[X%Q[X!][X~P$zO!]dX!c[X!cdX'ndX~P;aOP9VOQ9VO]cOb:mOc!jOhcOj9VOkcOlcOq9VOs9VOxRO{cO|cO}cO!TSO!_9XO!dUO!g9VO!h9VO!i9VO!j9VO!k9VO!n!iO#t!lO#x^O'Z'bO'dQO'mYO'z:kO~O!R9hO!S$]a~O]#qOh$OOj#rOk#qOl#qOq$POs9mOx#xO!T#yO!_:pO!d#vO#V9sO#t$TO$_9oO$a9qO$d$UO'Z&zO'd#sO~O#d'iO~P&-UO!S[X!SdX~P;aO#W9[O~O!]!wO#W9[O~O!{9kO~O#c9aO~O!{9tO!R'sX!S'sX~O!{9kO!R'qX!S'qX~O#W9uO~O'_9wO~P!#rO#W9|O~O#W9}O~O!]!wO#W:OO~O!]!wO#W9uO~O#m:PO~P#)gO#W:QO~O#W:RO~O#W:SO~O#W:TO~O#m:UO~P!#rO#m:VO~P!#rO#x~!b!r!t!u#U#V'z$_$a$d$u%P%Q%R%X%Z%^%_%a%c~UT#x'z#]}'W'X#z'W'Z'e~", - goto: "#Ed(XPPPPPPPP(YP(jP*^PPPP-uPP.[3n5b5uP5uPPP5uP7c5uP5uP7gPP7lP8Qk|}?O}!O>k!O!P?`!P!QCl!Q!R!0[!R![!1q![!]!7s!]!^!8V!^!_!8g!_!`!9d!`!a!:[!a!b!U#R#S2`#S#T!>i#T#o2`#o#p!>y#p#q!?O#q#r!?f#r#s!?x#s$f%T$f$g%c$g#BY2`#BY#BZ!@Y#BZ$IS2`$IS$I_!@Y$I_$I|2`$I|$I}!Bq$I}$JO!Bq$JO$JT2`$JT$JU!@Y$JU$KV2`$KV$KW!@Y$KW&FU2`&FU&FV!@Y&FV?HT2`?HT?HU!@Y?HU~2`W%YR$UWO!^%T!_#o%T#p~%T,T%jg$UW'W+{OX%TXY%cYZ%TZ[%c[p%Tpq%cq!^%T!_#o%T#p$f%T$f$g%c$g#BY%T#BY#BZ%c#BZ$IS%T$IS$I_%c$I_$JT%T$JT$JU%c$JU$KV%T$KV$KW%c$KW&FU%T&FU&FV%c&FV?HT%T?HT?HU%c?HU~%T,T'YR$UW'X+{O!^%T!_#o%T#p~%T$T'jS$UW!j#{O!^%T!_!`'v!`#o%T#p~%T$O'}S#e#v$UWO!^%T!_!`(Z!`#o%T#p~%T$O(bR#e#v$UWO!^%T!_#o%T#p~%T'u(rZ$UW]!ROY(kYZ)eZr(krs*rs!^(k!^!_+U!_#O(k#O#P-b#P#o(k#o#p+U#p~(k&r)jV$UWOr)ers*Ps!^)e!^!_*a!_#o)e#o#p*a#p~)e&r*WR$P&j$UWO!^%T!_#o%T#p~%T&j*dROr*ars*ms~*a&j*rO$P&j'u*{R$P&j$UW]!RO!^%T!_#o%T#p~%T'm+ZV]!ROY+UYZ*aZr+Urs+ps#O+U#O#P+w#P~+U'm+wO$P&j]!R'm+zROr+Urs,Ts~+U'm,[U$P&j]!ROY,nZr,nrs-Vs#O,n#O#P-[#P~,n!R,sU]!ROY,nZr,nrs-Vs#O,n#O#P-[#P~,n!R-[O]!R!R-_PO~,n'u-gV$UWOr(krs-|s!^(k!^!_+U!_#o(k#o#p+U#p~(k'u.VZ$P&j$UW]!ROY.xYZ%TZr.xrs/rs!^.x!^!_,n!_#O.x#O#P0S#P#o.x#o#p,n#p~.x!Z/PZ$UW]!ROY.xYZ%TZr.xrs/rs!^.x!^!_,n!_#O.x#O#P0S#P#o.x#o#p,n#p~.x!Z/yR$UW]!RO!^%T!_#o%T#p~%T!Z0XT$UWO!^.x!^!_,n!_#o.x#o#p,n#p~.xy0mZ$UWOt%Ttu1`u!^%T!_!c%T!c!}1`!}#R%T#R#S1`#S#T%T#T#o1`#p$g%T$g~1`y1g]$UW'mqOt%Ttu1`u!Q%T!Q![1`![!^%T!_!c%T!c!}1`!}#R%T#R#S1`#S#T%T#T#o1`#p$g%T$g~1`&i2k_$UW#zS'Z%k'epOt%Ttu2`u}%T}!O3j!O!Q%T!Q![2`![!^%T!_!c%T!c!}2`!}#R%T#R#S2`#S#T%T#T#o2`#p$g%T$g~2`[3q_$UW#zSOt%Ttu3ju}%T}!O3j!O!Q%T!Q![3j![!^%T!_!c%T!c!}3j!}#R%T#R#S3j#S#T%T#T#o3j#p$g%T$g~3j$O4wS#^#v$UWO!^%T!_!`5T!`#o%T#p~%T$O5[R$UW#o#vO!^%T!_#o%T#p~%T%r5lU'v%j$UWOv%Tvw6Ow!^%T!_!`5T!`#o%T#p~%T$O6VS$UW#i#vO!^%T!_!`5T!`#o%T#p~%T'u6jZ$UW]!ROY6cYZ7]Zw6cwx*rx!^6c!^!_8T!_#O6c#O#P:T#P#o6c#o#p8T#p~6c&r7bV$UWOw7]wx*Px!^7]!^!_7w!_#o7]#o#p7w#p~7]&j7zROw7wwx*mx~7w'm8YV]!ROY8TYZ7wZw8Twx+px#O8T#O#P8o#P~8T'm8rROw8Twx8{x~8T'm9SU$P&j]!ROY9fZw9fwx-Vx#O9f#O#P9}#P~9f!R9kU]!ROY9fZw9fwx-Vx#O9f#O#P9}#P~9f!R:QPO~9f'u:YV$UWOw6cwx:ox!^6c!^!_8T!_#o6c#o#p8T#p~6c'u:xZ$P&j$UW]!ROY;kYZ%TZw;kwx/rx!^;k!^!_9f!_#O;k#O#PW{!^%T!_!`5T!`#o%T#p~%T$O>_S#[#v$UWO!^%T!_!`5T!`#o%T#p~%T$u>rSj$m$UWO!^%T!_!`5T!`#o%T#p~%T&i?VR!R&a$UWO!^%T!_#o%T#p~%T&i?gVu%n$UWO!O%T!O!P?|!P!Q%T!Q![@r![!^%T!_#o%T#p~%Ty@RT$UWO!O%T!O!P@b!P!^%T!_#o%T#p~%Ty@iR!Qq$UWO!^%T!_#o%T#p~%Ty@yZ$UWkqO!Q%T!Q![@r![!^%T!_!g%T!g!hAl!h#R%T#R#S@r#S#X%T#X#YAl#Y#o%T#p~%TyAqZ$UWO{%T{|Bd|}%T}!OBd!O!Q%T!Q![CO![!^%T!_#R%T#R#SCO#S#o%T#p~%TyBiV$UWO!Q%T!Q![CO![!^%T!_#R%T#R#SCO#S#o%T#p~%TyCVV$UWkqO!Q%T!Q![CO![!^%T!_#R%T#R#SCO#S#o%T#p~%T,TCs`$UW#]#vOYDuYZ%TZzDuz{Jl{!PDu!P!Q!-e!Q!^Du!^!_Fx!_!`!.^!`!a!/]!a!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~DuXD|[$UW}POYDuYZ%TZ!PDu!P!QEr!Q!^Du!^!_Fx!_!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~DuXEy_$UW}PO!^%T!_#Z%T#Z#[Er#[#]%T#]#^Er#^#a%T#a#bEr#b#g%T#g#hEr#h#i%T#i#jEr#j#m%T#m#nEr#n#o%T#p~%TPF}V}POYFxZ!PFx!P!QGd!Q!}Fx!}#OG{#O#PHh#P~FxPGiU}P#Z#[Gd#]#^Gd#a#bGd#g#hGd#i#jGd#m#nGdPHOTOYG{Z#OG{#O#PH_#P#QFx#Q~G{PHbQOYG{Z~G{PHkQOYFxZ~FxXHvY$UWOYHqYZ%TZ!^Hq!^!_G{!_#OHq#O#PIf#P#QDu#Q#oHq#o#pG{#p~HqXIkV$UWOYHqYZ%TZ!^Hq!^!_G{!_#oHq#o#pG{#p~HqXJVV$UWOYDuYZ%TZ!^Du!^!_Fx!_#oDu#o#pFx#p~Du,TJs^$UW}POYJlYZKoZzJlz{NQ{!PJl!P!Q!,R!Q!^Jl!^!_!!]!_!}Jl!}#O!'|#O#P!+a#P#oJl#o#p!!]#p~Jl,TKtV$UWOzKoz{LZ{!^Ko!^!_M]!_#oKo#o#pM]#p~Ko,TL`X$UWOzKoz{LZ{!PKo!P!QL{!Q!^Ko!^!_M]!_#oKo#o#pM]#p~Ko,TMSR$UWU+{O!^%T!_#o%T#p~%T+{M`ROzM]z{Mi{~M]+{MlTOzM]z{Mi{!PM]!P!QM{!Q~M]+{NQOU+{,TNX^$UW}POYJlYZKoZzJlz{NQ{!PJl!P!Q! T!Q!^Jl!^!_!!]!_!}Jl!}#O!'|#O#P!+a#P#oJl#o#p!!]#p~Jl,T! ^_$UWU+{}PO!^%T!_#Z%T#Z#[Er#[#]%T#]#^Er#^#a%T#a#bEr#b#g%T#g#hEr#h#i%T#i#jEr#j#m%T#m#nEr#n#o%T#p~%T+{!!bY}POY!!]YZM]Zz!!]z{!#Q{!P!!]!P!Q!&x!Q!}!!]!}#O!$`#O#P!&f#P~!!]+{!#VY}POY!!]YZM]Zz!!]z{!#Q{!P!!]!P!Q!#u!Q!}!!]!}#O!$`#O#P!&f#P~!!]+{!#|UU+{}P#Z#[Gd#]#^Gd#a#bGd#g#hGd#i#jGd#m#nGd+{!$cWOY!$`YZM]Zz!$`z{!${{#O!$`#O#P!&S#P#Q!!]#Q~!$`+{!%OYOY!$`YZM]Zz!$`z{!${{!P!$`!P!Q!%n!Q#O!$`#O#P!&S#P#Q!!]#Q~!$`+{!%sTU+{OYG{Z#OG{#O#PH_#P#QFx#Q~G{+{!&VTOY!$`YZM]Zz!$`z{!${{~!$`+{!&iTOY!!]YZM]Zz!!]z{!#Q{~!!]+{!&}_}POzM]z{Mi{#ZM]#Z#[!&x#[#]M]#]#^!&x#^#aM]#a#b!&x#b#gM]#g#h!&x#h#iM]#i#j!&x#j#mM]#m#n!&x#n~M],T!(R[$UWOY!'|YZKoZz!'|z{!(w{!^!'|!^!_!$`!_#O!'|#O#P!*o#P#QJl#Q#o!'|#o#p!$`#p~!'|,T!(|^$UWOY!'|YZKoZz!'|z{!(w{!P!'|!P!Q!)x!Q!^!'|!^!_!$`!_#O!'|#O#P!*o#P#QJl#Q#o!'|#o#p!$`#p~!'|,T!*PY$UWU+{OYHqYZ%TZ!^Hq!^!_G{!_#OHq#O#PIf#P#QDu#Q#oHq#o#pG{#p~Hq,T!*tX$UWOY!'|YZKoZz!'|z{!(w{!^!'|!^!_!$`!_#o!'|#o#p!$`#p~!'|,T!+fX$UWOYJlYZKoZzJlz{NQ{!^Jl!^!_!!]!_#oJl#o#p!!]#p~Jl,T!,Yc$UW}POzKoz{LZ{!^Ko!^!_M]!_#ZKo#Z#[!,R#[#]Ko#]#^!,R#^#aKo#a#b!,R#b#gKo#g#h!,R#h#iKo#i#j!,R#j#mKo#m#n!,R#n#oKo#o#pM]#p~Ko,T!-lV$UWT+{OY!-eYZ%TZ!^!-e!^!_!.R!_#o!-e#o#p!.R#p~!-e+{!.WQT+{OY!.RZ~!.R$P!.g[$UW#o#v}POYDuYZ%TZ!PDu!P!QEr!Q!^Du!^!_Fx!_!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~Du]!/f[#wS$UW}POYDuYZ%TZ!PDu!P!QEr!Q!^Du!^!_Fx!_!}Du!}#OHq#O#PJQ#P#oDu#o#pFx#p~Duy!0cd$UWkqO!O%T!O!P@r!P!Q%T!Q![!1q![!^%T!_!g%T!g!hAl!h#R%T#R#S!1q#S#U%T#U#V!3X#V#X%T#X#YAl#Y#b%T#b#c!2w#c#d!4m#d#l%T#l#m!5{#m#o%T#p~%Ty!1x_$UWkqO!O%T!O!P@r!P!Q%T!Q![!1q![!^%T!_!g%T!g!hAl!h#R%T#R#S!1q#S#X%T#X#YAl#Y#b%T#b#c!2w#c#o%T#p~%Ty!3OR$UWkqO!^%T!_#o%T#p~%Ty!3^W$UWO!Q%T!Q!R!3v!R!S!3v!S!^%T!_#R%T#R#S!3v#S#o%T#p~%Ty!3}Y$UWkqO!Q%T!Q!R!3v!R!S!3v!S!^%T!_#R%T#R#S!3v#S#b%T#b#c!2w#c#o%T#p~%Ty!4rV$UWO!Q%T!Q!Y!5X!Y!^%T!_#R%T#R#S!5X#S#o%T#p~%Ty!5`X$UWkqO!Q%T!Q!Y!5X!Y!^%T!_#R%T#R#S!5X#S#b%T#b#c!2w#c#o%T#p~%Ty!6QZ$UWO!Q%T!Q![!6s![!^%T!_!c%T!c!i!6s!i#R%T#R#S!6s#S#T%T#T#Z!6s#Z#o%T#p~%Ty!6z]$UWkqO!Q%T!Q![!6s![!^%T!_!c%T!c!i!6s!i#R%T#R#S!6s#S#T%T#T#Z!6s#Z#b%T#b#c!2w#c#o%T#p~%T%w!7|R!]V$UW#m%hO!^%T!_#o%T#p~%T!P!8^R_w$UWO!^%T!_#o%T#p~%T+c!8rR'`d!a%Y#x&s'zP!P!Q!8{!^!_!9Q!_!`!9_W!9QO$WW#v!9VP#`#v!_!`!9Y#v!9_O#o#v#v!9dO#a#v%w!9kT!{%o$UWO!^%T!_!`'v!`!a!9z!a#o%T#p~%T$P!:RR#W#w$UWO!^%T!_#o%T#p~%T%w!:gT'_!s#a#v$RS$UWO!^%T!_!`!:v!`!a!;W!a#o%T#p~%T$O!:}R#a#v$UWO!^%T!_#o%T#p~%T$O!;_T#`#v$UWO!^%T!_!`5T!`!a!;n!a#o%T#p~%T$O!;uS#`#v$UWO!^%T!_!`5T!`#o%T#p~%T%w!]S#g#v$UWO!^%T!_!`5T!`#o%T#p~%T$P!>pR$UW'd#wO!^%T!_#o%T#p~%T~!?OO!T~%r!?VT'u%j$UWO!^%T!_!`5T!`#o%T#p#q!=P#q~%T$u!?oR!S$knQ$UWO!^%T!_#o%T#p~%TX!@PR!kP$UWO!^%T!_#o%T#p~%T,T!@gr$UW'W+{#zS'Z%k'epOX%TXY%cYZ%TZ[%c[p%Tpq%cqt%Ttu2`u}%T}!O3j!O!Q%T!Q![2`![!^%T!_!c%T!c!}2`!}#R%T#R#S2`#S#T%T#T#o2`#p$f%T$f$g%c$g#BY2`#BY#BZ!@Y#BZ$IS2`$IS$I_!@Y$I_$JT2`$JT$JU!@Y$JU$KV2`$KV$KW!@Y$KW&FU2`&FU&FV!@Y&FV?HT2`?HT?HU!@Y?HU~2`,T!CO_$UW'X+{#zS'Z%k'epOt%Ttu2`u}%T}!O3j!O!Q%T!Q![2`![!^%T!_!c%T!c!}2`!}#R%T#R#S2`#S#T%T#T#o2`#p$g%T$g~2`", - tokenizers: [noSemicolon, incdecToken, template, 0, 1, 2, 3, 4, 5, 6, 7, 8, insertSemicolon], - topRules: {"Script":[0,7]}, - dialects: {jsx: 11335, ts: 11337}, - dynamicPrecedences: {"149":1,"176":1}, - specialized: [{term: 287, get: (value, stack) => (tsExtends(value, stack) << 1)},{term: 287, get: value => spec_identifier[value] || -1},{term: 297, get: value => spec_word[value] || -1},{term: 63, get: value => spec_LessThan[value] || -1}], - tokenPrec: 11358 -}); +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} -exports.parser = parser; +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) -},{"@lezer/common":55,"@lezer/lr":57}],57:[function(require,module,exports){ -(function (process){ -'use strict'; + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} -Object.defineProperty(exports, '__esModule', { value: true }); +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) -var common = require('@lezer/common'); + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} -/// A parse stack. These are used internally by the parser to track -/// parsing progress. They also provide some properties and methods -/// that external code such as a tokenizer can use to get information -/// about the parse state. -class Stack { - /// @internal - constructor( - /// The parse that this stack is part of @internal - p, - /// Holds state, input pos, buffer index triplets for all but the - /// top state @internal - stack, - /// The current parse state @internal - state, - // The position at which the next reduce should take place. This - // can be less than `this.pos` when skipped expressions have been - // added to the stack (which should be moved outside of the next - // reduction) - /// @internal - reducePos, - /// The input position up to which this stack has parsed. - pos, - /// The dynamic score of the stack, including dynamic precedence - /// and error-recovery penalties - /// @internal - score, - // The output buffer. Holds (type, start, end, size) quads - // representing nodes created by the parser, where `size` is - // amount of buffer array entries covered by this node. - /// @internal - buffer, - // The base offset of the buffer. When stacks are split, the split - // instance shared the buffer history with its parent up to - // `bufferBase`, which is the absolute offset (including the - // offset of previous splits) into the buffer at which this stack - // starts writing. - /// @internal - bufferBase, - /// @internal - curContext, - /// @internal - lookAhead = 0, - // A parent stack from which this was split off, if any. This is - // set up so that it always points to a stack that has some - // additional buffer content, never to a stack with an equal - // `bufferBase`. - /// @internal - parent) { - this.p = p; - this.stack = stack; - this.state = state; - this.reducePos = reducePos; - this.pos = pos; - this.score = score; - this.buffer = buffer; - this.bufferBase = bufferBase; - this.curContext = curContext; - this.lookAhead = lookAhead; - this.parent = parent; - } - /// @internal - toString() { - return `[${this.stack.filter((_, i) => i % 3 == 0).concat(this.state)}]@${this.pos}${this.score ? "!" + this.score : ""}`; - } - // Start an empty stack - /// @internal - static start(p, state, pos = 0) { - let cx = p.parser.context; - return new Stack(p, [], state, pos, pos, 0, [], 0, cx ? new StackContext(cx, cx.start) : null, 0, null); - } - /// The stack's current [context](#lr.ContextTracker) value, if - /// any. Its type will depend on the context tracker's type - /// parameter, or it will be `null` if there is no context - /// tracker. - get context() { return this.curContext ? this.curContext.context : null; } - // Push a state onto the stack, tracking its start position as well - // as the buffer base at that point. - /// @internal - pushState(state, start) { - this.stack.push(this.state, start, this.bufferBase + this.buffer.length); - this.state = state; - } - // Apply a reduce action - /// @internal - reduce(action) { - let depth = action >> 19 /* ReduceDepthShift */, type = action & 65535 /* ValueMask */; - let { parser } = this.p; - let dPrec = parser.dynamicPrecedence(type); - if (dPrec) - this.score += dPrec; - if (depth == 0) { - this.pushState(parser.getGoto(this.state, type, true), this.reducePos); - // Zero-depth reductions are a special case—they add stuff to - // the stack without popping anything off. - if (type < parser.minRepeatTerm) - this.storeNode(type, this.reducePos, this.reducePos, 4, true); - this.reduceContext(type, this.reducePos); - return; - } - // Find the base index into `this.stack`, content after which will - // be dropped. Note that with `StayFlag` reductions we need to - // consume two extra frames (the dummy parent node for the skipped - // expression and the state that we'll be staying in, which should - // be moved to `this.state`). - let base = this.stack.length - ((depth - 1) * 3) - (action & 262144 /* StayFlag */ ? 6 : 0); - let start = this.stack[base - 2]; - let bufferBase = this.stack[base - 1], count = this.bufferBase + this.buffer.length - bufferBase; - // Store normal terms or `R -> R R` repeat reductions - if (type < parser.minRepeatTerm || (action & 131072 /* RepeatFlag */)) { - let pos = parser.stateFlag(this.state, 1 /* Skipped */) ? this.pos : this.reducePos; - this.storeNode(type, start, pos, count + 4, true); - } - if (action & 262144 /* StayFlag */) { - this.state = this.stack[base]; - } - else { - let baseStateID = this.stack[base - 3]; - this.state = parser.getGoto(baseStateID, type, true); - } - while (this.stack.length > base) - this.stack.pop(); - this.reduceContext(type, start); - } - // Shift a value into the buffer - /// @internal - storeNode(term, start, end, size = 4, isReduce = false) { - if (term == 0 /* Err */) { // Try to omit/merge adjacent error nodes - let cur = this, top = this.buffer.length; - if (top == 0 && cur.parent) { - top = cur.bufferBase - cur.parent.bufferBase; - cur = cur.parent; - } - if (top > 0 && cur.buffer[top - 4] == 0 /* Err */ && cur.buffer[top - 1] > -1) { - if (start == end) - return; - if (cur.buffer[top - 2] >= start) { - cur.buffer[top - 2] = end; - return; - } - } - } - if (!isReduce || this.pos == end) { // Simple case, just append - this.buffer.push(term, start, end, size); - } - else { // There may be skipped nodes that have to be moved forward - let index = this.buffer.length; - if (index > 0 && this.buffer[index - 4] != 0 /* Err */) - while (index > 0 && this.buffer[index - 2] > end) { - // Move this record forward - this.buffer[index] = this.buffer[index - 4]; - this.buffer[index + 1] = this.buffer[index - 3]; - this.buffer[index + 2] = this.buffer[index - 2]; - this.buffer[index + 3] = this.buffer[index - 1]; - index -= 4; - if (size > 4) - size -= 4; - } - this.buffer[index] = term; - this.buffer[index + 1] = start; - this.buffer[index + 2] = end; - this.buffer[index + 3] = size; - } - } - // Apply a shift action - /// @internal - shift(action, next, nextEnd) { - let start = this.pos; - if (action & 131072 /* GotoFlag */) { - this.pushState(action & 65535 /* ValueMask */, this.pos); - } - else if ((action & 262144 /* StayFlag */) == 0) { // Regular shift - let nextState = action, { parser } = this.p; - if (nextEnd > this.pos || next <= parser.maxNode) { - this.pos = nextEnd; - if (!parser.stateFlag(nextState, 1 /* Skipped */)) - this.reducePos = nextEnd; - } - this.pushState(nextState, start); - this.shiftContext(next, start); - if (next <= parser.maxNode) - this.buffer.push(next, start, nextEnd, 4); - } - else { // Shift-and-stay, which means this is a skipped token - this.pos = nextEnd; - this.shiftContext(next, start); - if (next <= this.p.parser.maxNode) - this.buffer.push(next, start, nextEnd, 4); - } - } - // Apply an action - /// @internal - apply(action, next, nextEnd) { - if (action & 65536 /* ReduceFlag */) - this.reduce(action); - else - this.shift(action, next, nextEnd); - } - // Add a prebuilt (reused) node into the buffer. - /// @internal - useNode(value, next) { - let index = this.p.reused.length - 1; - if (index < 0 || this.p.reused[index] != value) { - this.p.reused.push(value); - index++; - } - let start = this.pos; - this.reducePos = this.pos = start + value.length; - this.pushState(next, start); - this.buffer.push(index, start, this.reducePos, -1 /* size == -1 means this is a reused value */); - if (this.curContext) - this.updateContext(this.curContext.tracker.reuse(this.curContext.context, value, this, this.p.stream.reset(this.pos - value.length))); - } - // Split the stack. Due to the buffer sharing and the fact - // that `this.stack` tends to stay quite shallow, this isn't very - // expensive. - /// @internal - split() { - let parent = this; - let off = parent.buffer.length; - // Because the top of the buffer (after this.pos) may be mutated - // to reorder reductions and skipped tokens, and shared buffers - // should be immutable, this copies any outstanding skipped tokens - // to the new buffer, and puts the base pointer before them. - while (off > 0 && parent.buffer[off - 2] > parent.reducePos) - off -= 4; - let buffer = parent.buffer.slice(off), base = parent.bufferBase + off; - // Make sure parent points to an actual parent with content, if there is such a parent. - while (parent && base == parent.bufferBase) - parent = parent.parent; - return new Stack(this.p, this.stack.slice(), this.state, this.reducePos, this.pos, this.score, buffer, base, this.curContext, this.lookAhead, parent); - } - // Try to recover from an error by 'deleting' (ignoring) one token. - /// @internal - recoverByDelete(next, nextEnd) { - let isNode = next <= this.p.parser.maxNode; - if (isNode) - this.storeNode(next, this.pos, nextEnd, 4); - this.storeNode(0 /* Err */, this.pos, nextEnd, isNode ? 8 : 4); - this.pos = this.reducePos = nextEnd; - this.score -= 190 /* Delete */; - } - /// Check if the given term would be able to be shifted (optionally - /// after some reductions) on this stack. This can be useful for - /// external tokenizers that want to make sure they only provide a - /// given token when it applies. - canShift(term) { - for (let sim = new SimulatedStack(this);;) { - let action = this.p.parser.stateSlot(sim.state, 4 /* DefaultReduce */) || this.p.parser.hasAction(sim.state, term); - if ((action & 65536 /* ReduceFlag */) == 0) - return true; - if (action == 0) - return false; - sim.reduce(action); - } - } - // Apply up to Recover.MaxNext recovery actions that conceptually - // inserts some missing token or rule. - /// @internal - recoverByInsert(next) { - if (this.stack.length >= 300 /* MaxInsertStackDepth */) - return []; - let nextStates = this.p.parser.nextStates(this.state); - if (nextStates.length > 4 /* MaxNext */ << 1 || this.stack.length >= 120 /* DampenInsertStackDepth */) { - let best = []; - for (let i = 0, s; i < nextStates.length; i += 2) { - if ((s = nextStates[i + 1]) != this.state && this.p.parser.hasAction(s, next)) - best.push(nextStates[i], s); - } - if (this.stack.length < 120 /* DampenInsertStackDepth */) - for (let i = 0; best.length < 4 /* MaxNext */ << 1 && i < nextStates.length; i += 2) { - let s = nextStates[i + 1]; - if (!best.some((v, i) => (i & 1) && v == s)) - best.push(nextStates[i], s); - } - nextStates = best; - } - let result = []; - for (let i = 0; i < nextStates.length && result.length < 4 /* MaxNext */; i += 2) { - let s = nextStates[i + 1]; - if (s == this.state) - continue; - let stack = this.split(); - stack.storeNode(0 /* Err */, stack.pos, stack.pos, 4, true); - stack.pushState(s, this.pos); - stack.shiftContext(nextStates[i], this.pos); - stack.score -= 200 /* Insert */; - result.push(stack); - } - return result; - } - // Force a reduce, if possible. Return false if that can't - // be done. - /// @internal - forceReduce() { - let reduce = this.p.parser.stateSlot(this.state, 5 /* ForcedReduce */); - if ((reduce & 65536 /* ReduceFlag */) == 0) - return false; - let { parser } = this.p; - if (!parser.validAction(this.state, reduce)) { - let depth = reduce >> 19 /* ReduceDepthShift */, term = reduce & 65535 /* ValueMask */; - let target = this.stack.length - depth * 3; - if (target < 0 || parser.getGoto(this.stack[target], term, false) < 0) - return false; - this.storeNode(0 /* Err */, this.reducePos, this.reducePos, 4, true); - this.score -= 100 /* Reduce */; - } - this.reduce(reduce); - return true; - } - /// @internal - forceAll() { - while (!this.p.parser.stateFlag(this.state, 2 /* Accepting */)) { - if (!this.forceReduce()) { - this.storeNode(0 /* Err */, this.pos, this.pos, 4, true); - break; - } - } - return this; - } - /// Check whether this state has no further actions (assumed to be a direct descendant of the - /// top state, since any other states must be able to continue - /// somehow). @internal - get deadEnd() { - if (this.stack.length != 3) - return false; - let { parser } = this.p; - return parser.data[parser.stateSlot(this.state, 1 /* Actions */)] == 65535 /* End */ && - !parser.stateSlot(this.state, 4 /* DefaultReduce */); - } - /// Restart the stack (put it back in its start state). Only safe - /// when this.stack.length == 3 (state is directly below the top - /// state). @internal - restart() { - this.state = this.stack[0]; - this.stack.length = 0; - } - /// @internal - sameState(other) { - if (this.state != other.state || this.stack.length != other.stack.length) - return false; - for (let i = 0; i < this.stack.length; i += 3) - if (this.stack[i] != other.stack[i]) - return false; - return true; - } - /// Get the parser used by this stack. - get parser() { return this.p.parser; } - /// Test whether a given dialect (by numeric ID, as exported from - /// the terms file) is enabled. - dialectEnabled(dialectID) { return this.p.parser.dialect.flags[dialectID]; } - shiftContext(term, start) { - if (this.curContext) - this.updateContext(this.curContext.tracker.shift(this.curContext.context, term, this, this.p.stream.reset(start))); - } - reduceContext(term, start) { - if (this.curContext) - this.updateContext(this.curContext.tracker.reduce(this.curContext.context, term, this, this.p.stream.reset(start))); - } - /// @internal - emitContext() { - let last = this.buffer.length - 1; - if (last < 0 || this.buffer[last] != -3) - this.buffer.push(this.curContext.hash, this.reducePos, this.reducePos, -3); - } - /// @internal - emitLookAhead() { - let last = this.buffer.length - 1; - if (last < 0 || this.buffer[last] != -4) - this.buffer.push(this.lookAhead, this.reducePos, this.reducePos, -4); - } - updateContext(context) { - if (context != this.curContext.context) { - let newCx = new StackContext(this.curContext.tracker, context); - if (newCx.hash != this.curContext.hash) - this.emitContext(); - this.curContext = newCx; - } - } - /// @internal - setLookAhead(lookAhead) { - if (lookAhead > this.lookAhead) { - this.emitLookAhead(); - this.lookAhead = lookAhead; - } - } - /// @internal - close() { - if (this.curContext && this.curContext.tracker.strict) - this.emitContext(); - if (this.lookAhead > 0) - this.emitLookAhead(); - } +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) } -class StackContext { - constructor(tracker, context) { - this.tracker = tracker; - this.context = context; - this.hash = tracker.strict ? tracker.hash(context) : 0; - } + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) } -var Recover; -(function (Recover) { - Recover[Recover["Insert"] = 200] = "Insert"; - Recover[Recover["Delete"] = 190] = "Delete"; - Recover[Recover["Reduce"] = 100] = "Reduce"; - Recover[Recover["MaxNext"] = 4] = "MaxNext"; - Recover[Recover["MaxInsertStackDepth"] = 300] = "MaxInsertStackDepth"; - Recover[Recover["DampenInsertStackDepth"] = 120] = "DampenInsertStackDepth"; -})(Recover || (Recover = {})); -// Used to cheaply run some reductions to scan ahead without mutating -// an entire stack -class SimulatedStack { - constructor(start) { - this.start = start; - this.state = start.state; - this.stack = start.stack; - this.base = this.stack.length; - } - reduce(action) { - let term = action & 65535 /* ValueMask */, depth = action >> 19 /* ReduceDepthShift */; - if (depth == 0) { - if (this.stack == this.start.stack) - this.stack = this.stack.slice(); - this.stack.push(this.state, 0, 0); - this.base += 3; - } - else { - this.base -= (depth - 1) * 3; - } - let goto = this.start.p.parser.getGoto(this.stack[this.base - 3], term, true); - this.state = goto; - } + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) } -// This is given to `Tree.build` to build a buffer, and encapsulates -// the parent-stack-walking necessary to read the nodes. -class StackBufferCursor { - constructor(stack, pos, index) { - this.stack = stack; - this.pos = pos; - this.index = index; - this.buffer = stack.buffer; - if (this.index == 0) - this.maybeNext(); - } - static create(stack, pos = stack.bufferBase + stack.buffer.length) { - return new StackBufferCursor(stack, pos, pos - stack.bufferBase); - } - maybeNext() { - let next = this.stack.parent; - if (next != null) { - this.index = this.stack.bufferBase - next.bufferBase; - this.stack = next; - this.buffer = next.buffer; - } - } - get id() { return this.buffer[this.index - 4]; } - get start() { return this.buffer[this.index - 3]; } - get end() { return this.buffer[this.index - 2]; } - get size() { return this.buffer[this.index - 1]; } - next() { - this.index -= 4; - this.pos -= 4; - if (this.index == 0) - this.maybeNext(); - } - fork() { - return new StackBufferCursor(this.stack, this.pos, this.index); - } + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') } -class CachedToken { - constructor() { - this.start = -1; - this.value = -1; - this.end = -1; - this.extended = -1; - this.lookAhead = 0; - this.mask = 0; - this.context = 0; - } +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength } -const nullToken = new CachedToken; -/// [Tokenizers](#lr.ExternalTokenizer) interact with the input -/// through this interface. It presents the input as a stream of -/// characters, tracking lookahead and hiding the complexity of -/// [ranges](#common.Parser.parse^ranges) from tokenizer code. -class InputStream { - /// @internal - constructor( - /// @internal - input, - /// @internal - ranges) { - this.input = input; - this.ranges = ranges; - /// @internal - this.chunk = ""; - /// @internal - this.chunkOff = 0; - /// Backup chunk - this.chunk2 = ""; - this.chunk2Pos = 0; - /// The character code of the next code unit in the input, or -1 - /// when the stream is at the end of the input. - this.next = -1; - /// @internal - this.token = nullToken; - this.rangeIndex = 0; - this.pos = this.chunkPos = ranges[0].from; - this.range = ranges[0]; - this.end = ranges[ranges.length - 1].to; - this.readNext(); - } - resolveOffset(offset, assoc) { - let range = this.range, index = this.rangeIndex; - let pos = this.pos + offset; - while (pos < range.from) { - if (!index) - return null; - let next = this.ranges[--index]; - pos -= range.from - next.to; - range = next; - } - while (assoc < 0 ? pos > range.to : pos >= range.to) { - if (index == this.ranges.length - 1) - return null; - let next = this.ranges[++index]; - pos += next.from - range.to; - range = next; - } - return pos; - } - /// Look at a code unit near the stream position. `.peek(0)` equals - /// `.next`, `.peek(-1)` gives you the previous character, and so - /// on. - /// - /// Note that looking around during tokenizing creates dependencies - /// on potentially far-away content, which may reduce the - /// effectiveness incremental parsing—when looking forward—or even - /// cause invalid reparses when looking backward more than 25 code - /// units, since the library does not track lookbehind. - peek(offset) { - let idx = this.chunkOff + offset, pos, result; - if (idx >= 0 && idx < this.chunk.length) { - pos = this.pos + offset; - result = this.chunk.charCodeAt(idx); - } - else { - let resolved = this.resolveOffset(offset, 1); - if (resolved == null) - return -1; - pos = resolved; - if (pos >= this.chunk2Pos && pos < this.chunk2Pos + this.chunk2.length) { - result = this.chunk2.charCodeAt(pos - this.chunk2Pos); - } - else { - let i = this.rangeIndex, range = this.range; - while (range.to <= pos) - range = this.ranges[++i]; - this.chunk2 = this.input.chunk(this.chunk2Pos = pos); - if (pos + this.chunk2.length > range.to) - this.chunk2 = this.chunk2.slice(0, range.to - pos); - result = this.chunk2.charCodeAt(0); - } - } - if (pos >= this.token.lookAhead) - this.token.lookAhead = pos + 1; - return result; - } - /// Accept a token. By default, the end of the token is set to the - /// current stream position, but you can pass an offset (relative to - /// the stream position) to change that. - acceptToken(token, endOffset = 0) { - let end = endOffset ? this.resolveOffset(endOffset, -1) : this.pos; - if (end == null || end < this.token.start) - throw new RangeError("Token end out of bounds"); - this.token.value = token; - this.token.end = end; - } - getChunk() { - if (this.pos >= this.chunk2Pos && this.pos < this.chunk2Pos + this.chunk2.length) { - let { chunk, chunkPos } = this; - this.chunk = this.chunk2; - this.chunkPos = this.chunk2Pos; - this.chunk2 = chunk; - this.chunk2Pos = chunkPos; - this.chunkOff = this.pos - this.chunkPos; - } - else { - this.chunk2 = this.chunk; - this.chunk2Pos = this.chunkPos; - let nextChunk = this.input.chunk(this.pos); - let end = this.pos + nextChunk.length; - this.chunk = end > this.range.to ? nextChunk.slice(0, this.range.to - this.pos) : nextChunk; - this.chunkPos = this.pos; - this.chunkOff = 0; - } - } - readNext() { - if (this.chunkOff >= this.chunk.length) { - this.getChunk(); - if (this.chunkOff == this.chunk.length) - return this.next = -1; - } - return this.next = this.chunk.charCodeAt(this.chunkOff); - } - /// Move the stream forward N (defaults to 1) code units. Returns - /// the new value of [`next`](#lr.InputStream.next). - advance(n = 1) { - this.chunkOff += n; - while (this.pos + n >= this.range.to) { - if (this.rangeIndex == this.ranges.length - 1) - return this.setDone(); - n -= this.range.to - this.pos; - this.range = this.ranges[++this.rangeIndex]; - this.pos = this.range.from; - } - this.pos += n; - if (this.pos >= this.token.lookAhead) - this.token.lookAhead = this.pos + 1; - return this.readNext(); - } - setDone() { - this.pos = this.chunkPos = this.end; - this.range = this.ranges[this.rangeIndex = this.ranges.length - 1]; - this.chunk = ""; - return this.next = -1; - } - /// @internal - reset(pos, token) { - if (token) { - this.token = token; - token.start = pos; - token.lookAhead = pos + 1; - token.value = token.extended = -1; - } - else { - this.token = nullToken; - } - if (this.pos != pos) { - this.pos = pos; - if (pos == this.end) { - this.setDone(); - return this; - } - while (pos < this.range.from) - this.range = this.ranges[--this.rangeIndex]; - while (pos >= this.range.to) - this.range = this.ranges[++this.rangeIndex]; - if (pos >= this.chunkPos && pos < this.chunkPos + this.chunk.length) { - this.chunkOff = pos - this.chunkPos; - } - else { - this.chunk = ""; - this.chunkOff = 0; - } - this.readNext(); - } - return this; - } - /// @internal - read(from, to) { - if (from >= this.chunkPos && to <= this.chunkPos + this.chunk.length) - return this.chunk.slice(from - this.chunkPos, to - this.chunkPos); - if (from >= this.chunk2Pos && to <= this.chunk2Pos + this.chunk2.length) - return this.chunk2.slice(from - this.chunk2Pos, to - this.chunk2Pos); - if (from >= this.range.from && to <= this.range.to) - return this.input.read(from, to); - let result = ""; - for (let r of this.ranges) { - if (r.from >= to) - break; - if (r.to > from) - result += this.input.read(Math.max(r.from, from), Math.min(r.to, to)); - } - return result; - } + +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength } -/// @internal -class TokenGroup { - constructor(data, id) { - this.data = data; - this.id = id; - } - token(input, stack) { readToken(this.data, input, stack, this.id); } + +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + this[offset] = (value & 0xff) + return offset + 1 } -TokenGroup.prototype.contextual = TokenGroup.prototype.fallback = TokenGroup.prototype.extend = false; -/// `@external tokens` declarations in the grammar should resolve to -/// an instance of this class. -class ExternalTokenizer { - /// Create a tokenizer. The first argument is the function that, - /// given an input stream, scans for the types of tokens it - /// recognizes at the stream's position, and calls - /// [`acceptToken`](#lr.InputStream.acceptToken) when it finds - /// one. - constructor( - /// @internal - token, options = {}) { - this.token = token; - this.contextual = !!options.contextual; - this.fallback = !!options.fallback; - this.extend = !!options.extend; - } + +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 } -// Tokenizer data is stored a big uint16 array containing, for each -// state: -// -// - A group bitmask, indicating what token groups are reachable from -// this state, so that paths that can only lead to tokens not in -// any of the current groups can be cut off early. -// -// - The position of the end of the state's sequence of accepting -// tokens -// -// - The number of outgoing edges for the state -// -// - The accepting tokens, as (token id, group mask) pairs -// -// - The outgoing edges, as (start character, end character, state -// index) triples, with end character being exclusive -// -// This function interprets that data, running through a stream as -// long as new states with the a matching group mask can be reached, -// and updating `token` when it matches a token. -function readToken(data, input, stack, group) { - let state = 0, groupMask = 1 << group, { parser } = stack.p, { dialect } = parser; - scan: for (;;) { - if ((groupMask & data[state]) == 0) - break; - let accEnd = data[state + 1]; - // Check whether this state can lead to a token in the current group - // Accept tokens in this state, possibly overwriting - // lower-precedence / shorter tokens - for (let i = state + 3; i < accEnd; i += 2) - if ((data[i + 1] & groupMask) > 0) { - let term = data[i]; - if (dialect.allows(term) && - (input.token.value == -1 || input.token.value == term || parser.overrides(term, input.token.value))) { - input.acceptToken(term); - break; - } - } - // Do a binary search on the state's edges - for (let next = input.next, low = 0, high = data[state + 2]; low < high;) { - let mid = (low + high) >> 1; - let index = accEnd + mid + (mid << 1); - let from = data[index], to = data[index + 1]; - if (next < from) - high = mid; - else if (next >= to) - low = mid + 1; - else { - state = data[index + 2]; - input.advance(); - continue scan; - } - } - break; - } + +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 } -// See lezer-generator/src/encode.ts for comments about the encoding -// used here -function decodeArray(input, Type = Uint16Array) { - if (typeof input != "string") - return input; - let array = null; - for (let pos = 0, out = 0; pos < input.length;) { - let value = 0; - for (;;) { - let next = input.charCodeAt(pos++), stop = false; - if (next == 126 /* BigValCode */) { - value = 65535 /* BigVal */; - break; - } - if (next >= 92 /* Gap2 */) - next--; - if (next >= 34 /* Gap1 */) - next--; - let digit = next - 32 /* Start */; - if (digit >= 46 /* Base */) { - digit -= 46 /* Base */; - stop = true; - } - value += digit; - if (stop) - break; - value *= 46 /* Base */; - } - if (array) - array[out++] = value; - else - array = new Type(value); - } - return array; +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + return offset + 4 } -// FIXME find some way to reduce recovery work done when the input -// doesn't match the grammar at all. -// Environment variable used to control console output -const verbose = typeof process != "undefined" && /\bparse\b/.test(process.env.LOG); -let stackIDs = null; -var Safety; -(function (Safety) { - Safety[Safety["Margin"] = 25] = "Margin"; -})(Safety || (Safety = {})); -function cutAt(tree, pos, side) { - let cursor = tree.fullCursor(); - cursor.moveTo(pos); - for (;;) { - if (!(side < 0 ? cursor.childBefore(pos) : cursor.childAfter(pos))) - for (;;) { - if ((side < 0 ? cursor.to < pos : cursor.from > pos) && !cursor.type.isError) - return side < 0 ? Math.max(0, Math.min(cursor.to - 1, pos - 25 /* Margin */)) - : Math.min(tree.length, Math.max(cursor.from + 1, pos + 25 /* Margin */)); - if (side < 0 ? cursor.prevSibling() : cursor.nextSibling()) - break; - if (!cursor.parent()) - return side < 0 ? 0 : tree.length; - } - } +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 } -class FragmentCursor { - constructor(fragments, nodeSet) { - this.fragments = fragments; - this.nodeSet = nodeSet; - this.i = 0; - this.fragment = null; - this.safeFrom = -1; - this.safeTo = -1; - this.trees = []; - this.start = []; - this.index = []; - this.nextFragment(); - } - nextFragment() { - let fr = this.fragment = this.i == this.fragments.length ? null : this.fragments[this.i++]; - if (fr) { - this.safeFrom = fr.openStart ? cutAt(fr.tree, fr.from + fr.offset, 1) - fr.offset : fr.from; - this.safeTo = fr.openEnd ? cutAt(fr.tree, fr.to + fr.offset, -1) - fr.offset : fr.to; - while (this.trees.length) { - this.trees.pop(); - this.start.pop(); - this.index.pop(); - } - this.trees.push(fr.tree); - this.start.push(-fr.offset); - this.index.push(0); - this.nextStart = this.safeFrom; - } - else { - this.nextStart = 1e9; - } - } - // `pos` must be >= any previously given `pos` for this cursor - nodeAt(pos) { - if (pos < this.nextStart) - return null; - while (this.fragment && this.safeTo <= pos) - this.nextFragment(); - if (!this.fragment) - return null; - for (;;) { - let last = this.trees.length - 1; - if (last < 0) { // End of tree - this.nextFragment(); - return null; - } - let top = this.trees[last], index = this.index[last]; - if (index == top.children.length) { - this.trees.pop(); - this.start.pop(); - this.index.pop(); - continue; - } - let next = top.children[index]; - let start = this.start[last] + top.positions[index]; - if (start > pos) { - this.nextStart = start; - return null; - } - if (next instanceof common.Tree) { - if (start == pos) { - if (start < this.safeFrom) - return null; - let end = start + next.length; - if (end <= this.safeTo) { - let lookAhead = next.prop(common.NodeProp.lookAhead); - if (!lookAhead || end + lookAhead < this.fragment.to) - return next; - } - } - this.index[last]++; - if (start + next.length >= Math.max(this.safeFrom, pos)) { // Enter this node - this.trees.push(next); - this.start.push(start); - this.index.push(0); - } - } - else { - this.index[last]++; - this.nextStart = start + next.length; - } - } + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = 0 + var mul = 1 + var sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength } -class TokenCache { - constructor(parser, stream) { - this.stream = stream; - this.tokens = []; - this.mainToken = null; - this.actions = []; - this.tokens = parser.tokenizers.map(_ => new CachedToken); - } - getActions(stack) { - let actionIndex = 0; - let main = null; - let { parser } = stack.p, { tokenizers } = parser; - let mask = parser.stateSlot(stack.state, 3 /* TokenizerMask */); - let context = stack.curContext ? stack.curContext.hash : 0; - let lookAhead = 0; - for (let i = 0; i < tokenizers.length; i++) { - if (((1 << i) & mask) == 0) - continue; - let tokenizer = tokenizers[i], token = this.tokens[i]; - if (main && !tokenizer.fallback) - continue; - if (tokenizer.contextual || token.start != stack.pos || token.mask != mask || token.context != context) { - this.updateCachedToken(token, tokenizer, stack); - token.mask = mask; - token.context = context; - } - if (token.lookAhead > token.end + 25 /* Margin */) - lookAhead = Math.max(token.lookAhead, lookAhead); - if (token.value != 0 /* Err */) { - let startIndex = actionIndex; - if (token.extended > -1) - actionIndex = this.addActions(stack, token.extended, token.end, actionIndex); - actionIndex = this.addActions(stack, token.value, token.end, actionIndex); - if (!tokenizer.extend) { - main = token; - if (actionIndex > startIndex) - break; - } - } - } - while (this.actions.length > actionIndex) - this.actions.pop(); - if (lookAhead) - stack.setLookAhead(lookAhead); - if (!main && stack.pos == this.stream.end) { - main = new CachedToken; - main.value = stack.p.parser.eofTerm; - main.start = main.end = stack.pos; - actionIndex = this.addActions(stack, main.value, main.end, actionIndex); - } - this.mainToken = main; - return this.actions; - } - getMainToken(stack) { - if (this.mainToken) - return this.mainToken; - let main = new CachedToken, { pos, p } = stack; - main.start = pos; - main.end = Math.min(pos + 1, p.stream.end); - main.value = pos == p.stream.end ? p.parser.eofTerm : 0 /* Err */; - return main; - } - updateCachedToken(token, tokenizer, stack) { - tokenizer.token(this.stream.reset(stack.pos, token), stack); - if (token.value > -1) { - let { parser } = stack.p; - for (let i = 0; i < parser.specialized.length; i++) - if (parser.specialized[i] == token.value) { - let result = parser.specializers[i](this.stream.read(token.start, token.end), stack); - if (result >= 0 && stack.p.parser.dialect.allows(result >> 1)) { - if ((result & 1) == 0 /* Specialize */) - token.value = result >> 1; - else - token.extended = result >> 1; - break; - } - } - } - else { - token.value = 0 /* Err */; - token.end = Math.min(stack.p.stream.end, stack.pos + 1); - } - } - putAction(action, token, end, index) { - // Don't add duplicate actions - for (let i = 0; i < index; i += 3) - if (this.actions[i] == action) - return index; - this.actions[index++] = action; - this.actions[index++] = token; - this.actions[index++] = end; - return index; - } - addActions(stack, token, end, index) { - let { state } = stack, { parser } = stack.p, { data } = parser; - for (let set = 0; set < 2; set++) { - for (let i = parser.stateSlot(state, set ? 2 /* Skip */ : 1 /* Actions */);; i += 3) { - if (data[i] == 65535 /* End */) { - if (data[i + 1] == 1 /* Next */) { - i = pair(data, i + 2); - } - else { - if (index == 0 && data[i + 1] == 2 /* Other */) - index = this.putAction(pair(data, i + 2), token, end, index); - break; - } - } - if (data[i] == token) - index = this.putAction(pair(data, i + 1), token, end, index); - } - } - return index; + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = byteLength - 1 + var mul = 1 + var sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength } -var Rec; -(function (Rec) { - Rec[Rec["Distance"] = 5] = "Distance"; - Rec[Rec["MaxRemainingPerStep"] = 3] = "MaxRemainingPerStep"; - // When two stacks have been running independently long enough to - // add this many elements to their buffers, prune one. - Rec[Rec["MinBufferLengthPrune"] = 500] = "MinBufferLengthPrune"; - Rec[Rec["ForceReduceLimit"] = 10] = "ForceReduceLimit"; - // Once a stack reaches this depth (in .stack.length) force-reduce - // it back to CutTo to avoid creating trees that overflow the stack - // on recursive traversal. - Rec[Rec["CutDepth"] = 15000] = "CutDepth"; - Rec[Rec["CutTo"] = 9000] = "CutTo"; -})(Rec || (Rec = {})); -class Parse { - constructor(parser, input, fragments, ranges) { - this.parser = parser; - this.input = input; - this.ranges = ranges; - this.recovering = 0; - this.nextStackID = 0x2654; // ♔, ♕, ♖, ♗, ♘, ♙, ♠, ♡, ♢, ♣, ♤, ♥, ♦, ♧ - this.minStackPos = 0; - this.reused = []; - this.stoppedAt = null; - this.stream = new InputStream(input, ranges); - this.tokens = new TokenCache(parser, this.stream); - this.topTerm = parser.top[1]; - let { from } = ranges[0]; - this.stacks = [Stack.start(this, parser.top[0], from)]; - this.fragments = fragments.length && this.stream.end - from > parser.bufferLength * 4 - ? new FragmentCursor(fragments, parser.nodeSet) : null; - } - get parsedPos() { - return this.minStackPos; - } - // Move the parser forward. This will process all parse stacks at - // `this.pos` and try to advance them to a further position. If no - // stack for such a position is found, it'll start error-recovery. - // - // When the parse is finished, this will return a syntax tree. When - // not, it returns `null`. - advance() { - let stacks = this.stacks, pos = this.minStackPos; - // This will hold stacks beyond `pos`. - let newStacks = this.stacks = []; - let stopped, stoppedTokens; - // Keep advancing any stacks at `pos` until they either move - // forward or can't be advanced. Gather stacks that can't be - // advanced further in `stopped`. - for (let i = 0; i < stacks.length; i++) { - let stack = stacks[i]; - for (;;) { - this.tokens.mainToken = null; - if (stack.pos > pos) { - newStacks.push(stack); - } - else if (this.advanceStack(stack, newStacks, stacks)) { - continue; - } - else { - if (!stopped) { - stopped = []; - stoppedTokens = []; - } - stopped.push(stack); - let tok = this.tokens.getMainToken(stack); - stoppedTokens.push(tok.value, tok.end); - } - break; - } - } - if (!newStacks.length) { - let finished = stopped && findFinished(stopped); - if (finished) - return this.stackToTree(finished); - if (this.parser.strict) { - if (verbose && stopped) - console.log("Stuck with token " + (this.tokens.mainToken ? this.parser.getName(this.tokens.mainToken.value) : "none")); - throw new SyntaxError("No parse at " + pos); - } - if (!this.recovering) - this.recovering = 5 /* Distance */; - } - if (this.recovering && stopped) { - let finished = this.stoppedAt != null && stopped[0].pos > this.stoppedAt ? stopped[0] - : this.runRecovery(stopped, stoppedTokens, newStacks); - if (finished) - return this.stackToTree(finished.forceAll()); - } - if (this.recovering) { - let maxRemaining = this.recovering == 1 ? 1 : this.recovering * 3 /* MaxRemainingPerStep */; - if (newStacks.length > maxRemaining) { - newStacks.sort((a, b) => b.score - a.score); - while (newStacks.length > maxRemaining) - newStacks.pop(); - } - if (newStacks.some(s => s.reducePos > pos)) - this.recovering--; - } - else if (newStacks.length > 1) { - // Prune stacks that are in the same state, or that have been - // running without splitting for a while, to avoid getting stuck - // with multiple successful stacks running endlessly on. - outer: for (let i = 0; i < newStacks.length - 1; i++) { - let stack = newStacks[i]; - for (let j = i + 1; j < newStacks.length; j++) { - let other = newStacks[j]; - if (stack.sameState(other) || - stack.buffer.length > 500 /* MinBufferLengthPrune */ && other.buffer.length > 500 /* MinBufferLengthPrune */) { - if (((stack.score - other.score) || (stack.buffer.length - other.buffer.length)) > 0) { - newStacks.splice(j--, 1); - } - else { - newStacks.splice(i--, 1); - continue outer; - } - } - } - } - } - this.minStackPos = newStacks[0].pos; - for (let i = 1; i < newStacks.length; i++) - if (newStacks[i].pos < this.minStackPos) - this.minStackPos = newStacks[i].pos; - return null; - } - stopAt(pos) { - if (this.stoppedAt != null && this.stoppedAt < pos) - throw new RangeError("Can't move stoppedAt forward"); - this.stoppedAt = pos; - } - // Returns an updated version of the given stack, or null if the - // stack can't advance normally. When `split` and `stacks` are - // given, stacks split off by ambiguous operations will be pushed to - // `split`, or added to `stacks` if they move `pos` forward. - advanceStack(stack, stacks, split) { - let start = stack.pos, { parser } = this; - let base = verbose ? this.stackID(stack) + " -> " : ""; - if (this.stoppedAt != null && start > this.stoppedAt) - return stack.forceReduce() ? stack : null; - if (this.fragments) { - let strictCx = stack.curContext && stack.curContext.tracker.strict, cxHash = strictCx ? stack.curContext.hash : 0; - for (let cached = this.fragments.nodeAt(start); cached;) { - let match = this.parser.nodeSet.types[cached.type.id] == cached.type ? parser.getGoto(stack.state, cached.type.id) : -1; - if (match > -1 && cached.length && (!strictCx || (cached.prop(common.NodeProp.contextHash) || 0) == cxHash)) { - stack.useNode(cached, match); - if (verbose) - console.log(base + this.stackID(stack) + ` (via reuse of ${parser.getName(cached.type.id)})`); - return true; - } - if (!(cached instanceof common.Tree) || cached.children.length == 0 || cached.positions[0] > 0) - break; - let inner = cached.children[0]; - if (inner instanceof common.Tree && cached.positions[0] == 0) - cached = inner; - else - break; - } - } - let defaultReduce = parser.stateSlot(stack.state, 4 /* DefaultReduce */); - if (defaultReduce > 0) { - stack.reduce(defaultReduce); - if (verbose) - console.log(base + this.stackID(stack) + ` (via always-reduce ${parser.getName(defaultReduce & 65535 /* ValueMask */)})`); - return true; - } - if (stack.stack.length >= 15000 /* CutDepth */) { - while (stack.stack.length > 9000 /* CutTo */ && stack.forceReduce()) { } - } - let actions = this.tokens.getActions(stack); - for (let i = 0; i < actions.length;) { - let action = actions[i++], term = actions[i++], end = actions[i++]; - let last = i == actions.length || !split; - let localStack = last ? stack : stack.split(); - localStack.apply(action, term, end); - if (verbose) - console.log(base + this.stackID(localStack) + ` (via ${(action & 65536 /* ReduceFlag */) == 0 ? "shift" - : `reduce of ${parser.getName(action & 65535 /* ValueMask */)}`} for ${parser.getName(term)} @ ${start}${localStack == stack ? "" : ", split"})`); - if (last) - return true; - else if (localStack.pos > start) - stacks.push(localStack); - else - split.push(localStack); - } - return false; - } - // Advance a given stack forward as far as it will go. Returns the - // (possibly updated) stack if it got stuck, or null if it moved - // forward and was given to `pushStackDedup`. - advanceFully(stack, newStacks) { - let pos = stack.pos; - for (;;) { - if (!this.advanceStack(stack, null, null)) - return false; - if (stack.pos > pos) { - pushStackDedup(stack, newStacks); - return true; - } - } - } - runRecovery(stacks, tokens, newStacks) { - let finished = null, restarted = false; - for (let i = 0; i < stacks.length; i++) { - let stack = stacks[i], token = tokens[i << 1], tokenEnd = tokens[(i << 1) + 1]; - let base = verbose ? this.stackID(stack) + " -> " : ""; - if (stack.deadEnd) { - if (restarted) - continue; - restarted = true; - stack.restart(); - if (verbose) - console.log(base + this.stackID(stack) + " (restarted)"); - let done = this.advanceFully(stack, newStacks); - if (done) - continue; - } - let force = stack.split(), forceBase = base; - for (let j = 0; force.forceReduce() && j < 10 /* ForceReduceLimit */; j++) { - if (verbose) - console.log(forceBase + this.stackID(force) + " (via force-reduce)"); - let done = this.advanceFully(force, newStacks); - if (done) - break; - if (verbose) - forceBase = this.stackID(force) + " -> "; - } - for (let insert of stack.recoverByInsert(token)) { - if (verbose) - console.log(base + this.stackID(insert) + " (via recover-insert)"); - this.advanceFully(insert, newStacks); - } - if (this.stream.end > stack.pos) { - if (tokenEnd == stack.pos) { - tokenEnd++; - token = 0 /* Err */; - } - stack.recoverByDelete(token, tokenEnd); - if (verbose) - console.log(base + this.stackID(stack) + ` (via recover-delete ${this.parser.getName(token)})`); - pushStackDedup(stack, newStacks); - } - else if (!finished || finished.score < stack.score) { - finished = stack; - } - } - return finished; - } - // Convert the stack's buffer to a syntax tree. - stackToTree(stack) { - stack.close(); - return common.Tree.build({ buffer: StackBufferCursor.create(stack), - nodeSet: this.parser.nodeSet, - topID: this.topTerm, - maxBufferLength: this.parser.bufferLength, - reused: this.reused, - start: this.ranges[0].from, - length: stack.pos - this.ranges[0].from, - minRepeatType: this.parser.minRepeatTerm }); - } - stackID(stack) { - let id = (stackIDs || (stackIDs = new WeakMap)).get(stack); - if (!id) - stackIDs.set(stack, id = String.fromCodePoint(this.nextStackID++)); - return id + stack; - } + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 } -function pushStackDedup(stack, newStacks) { - for (let i = 0; i < newStacks.length; i++) { - let other = newStacks[i]; - if (other.pos == stack.pos && other.sameState(stack)) { - if (newStacks[i].score < stack.score) - newStacks[i] = stack; - return; - } - } - newStacks.push(stack); + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 } -class Dialect { - constructor(source, flags, disabled) { - this.source = source; - this.flags = flags; - this.disabled = disabled; - } - allows(term) { return !this.disabled || this.disabled[term] == 0; } + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 } -const id = x => x; -/// Context trackers are used to track stateful context (such as -/// indentation in the Python grammar, or parent elements in the XML -/// grammar) needed by external tokenizers. You declare them in a -/// grammar file as `@context exportName from "module"`. -/// -/// Context values should be immutable, and can be updated (replaced) -/// on shift or reduce actions. -/// -/// The export used in a `@context` declaration should be of this -/// type. -class ContextTracker { - /// Define a context tracker. - constructor(spec) { - this.start = spec.start; - this.shift = spec.shift || id; - this.reduce = spec.reduce || id; - this.reuse = spec.reuse || id; - this.hash = spec.hash || (() => 0); - this.strict = spec.strict !== false; - } + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) } -/// A parser holds the parse tables for a given grammar, as generated -/// by `lezer-generator`. -class LRParser extends common.Parser { - /// @internal - constructor(spec) { - super(); - /// @internal - this.wrappers = []; - if (spec.version != 13 /* Version */) - throw new RangeError(`Parser version (${spec.version}) doesn't match runtime version (${13 /* Version */})`); - let nodeNames = spec.nodeNames.split(" "); - this.minRepeatTerm = nodeNames.length; - for (let i = 0; i < spec.repeatNodeCount; i++) - nodeNames.push(""); - let topTerms = Object.keys(spec.topRules).map(r => spec.topRules[r][1]); - let nodeProps = []; - for (let i = 0; i < nodeNames.length; i++) - nodeProps.push([]); - function setProp(nodeID, prop, value) { - nodeProps[nodeID].push([prop, prop.deserialize(String(value))]); - } - if (spec.nodeProps) - for (let propSpec of spec.nodeProps) { - let prop = propSpec[0]; - for (let i = 1; i < propSpec.length;) { - let next = propSpec[i++]; - if (next >= 0) { - setProp(next, prop, propSpec[i++]); - } - else { - let value = propSpec[i + -next]; - for (let j = -next; j > 0; j--) - setProp(propSpec[i++], prop, value); - i++; - } - } - } - this.nodeSet = new common.NodeSet(nodeNames.map((name, i) => common.NodeType.define({ - name: i >= this.minRepeatTerm ? undefined : name, - id: i, - props: nodeProps[i], - top: topTerms.indexOf(i) > -1, - error: i == 0, - skipped: spec.skippedNodes && spec.skippedNodes.indexOf(i) > -1 - }))); - this.strict = false; - this.bufferLength = common.DefaultBufferLength; - let tokenArray = decodeArray(spec.tokenData); - this.context = spec.context; - this.specialized = new Uint16Array(spec.specialized ? spec.specialized.length : 0); - this.specializers = []; - if (spec.specialized) - for (let i = 0; i < spec.specialized.length; i++) { - this.specialized[i] = spec.specialized[i].term; - this.specializers[i] = spec.specialized[i].get; - } - this.states = decodeArray(spec.states, Uint32Array); - this.data = decodeArray(spec.stateData); - this.goto = decodeArray(spec.goto); - this.maxTerm = spec.maxTerm; - this.tokenizers = spec.tokenizers.map(value => typeof value == "number" ? new TokenGroup(tokenArray, value) : value); - this.topRules = spec.topRules; - this.dialects = spec.dialects || {}; - this.dynamicPrecedences = spec.dynamicPrecedences || null; - this.tokenPrecTable = spec.tokenPrec; - this.termNames = spec.termNames || null; - this.maxNode = this.nodeSet.types.length - 1; - this.dialect = this.parseDialect(); - this.top = this.topRules[Object.keys(this.topRules)[0]]; - } - createParse(input, fragments, ranges) { - let parse = new Parse(this, input, fragments, ranges); - for (let w of this.wrappers) - parse = w(parse, input, fragments, ranges); - return parse; + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + var len = end - start + + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (var i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start] } - /// Get a goto table entry @internal - getGoto(state, term, loose = false) { - let table = this.goto; - if (term >= table[0]) - return -1; - for (let pos = table[term + 1];;) { - let groupTag = table[pos++], last = groupTag & 1; - let target = table[pos++]; - if (last && loose) - return target; - for (let end = pos + (groupTag >> 1); pos < end; pos++) - if (table[pos] == state) - return target; - if (last) - return -1; - } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, end), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length } - /// Check if this state has an action for a given terminal @internal - hasAction(state, terminal) { - let data = this.data; - for (let set = 0; set < 2; set++) { - for (let i = this.stateSlot(state, set ? 2 /* Skip */ : 1 /* Actions */), next;; i += 3) { - if ((next = data[i]) == 65535 /* End */) { - if (data[i + 1] == 1 /* Next */) - next = data[i = pair(data, i + 2)]; - else if (data[i + 1] == 2 /* Other */) - return pair(data, i + 2); - else - break; - } - if (next == terminal || next == 0 /* Err */) - return pair(data, i + 1); - } - } - return 0; + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') } - /// @internal - stateSlot(state, slot) { - return this.states[(state * 6 /* Size */) + slot]; + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) } - /// @internal - stateFlag(state, flag) { - return (this.stateSlot(state, 0 /* Flags */) & flag) > 0; + if (val.length === 1) { + var code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } } - /// @internal - validAction(state, action) { - if (action == this.stateSlot(state, 4 /* DefaultReduce */)) - return true; - for (let i = this.stateSlot(state, 1 /* Actions */);; i += 3) { - if (this.data[i] == 65535 /* End */) { - if (this.data[i + 1] == 1 /* Next */) - i = pair(this.data, i + 2); - else - return false; - } - if (action == pair(this.data, i + 1)) - return true; - } + } else if (typeof val === 'number') { + val = val & 255 + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + var i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val } - /// Get the states that can follow this one through shift actions or - /// goto jumps. @internal - nextStates(state) { - let result = []; - for (let i = this.stateSlot(state, 1 /* Actions */);; i += 3) { - if (this.data[i] == 65535 /* End */) { - if (this.data[i + 1] == 1 /* Next */) - i = pair(this.data, i + 2); - else - break; - } - if ((this.data[i + 2] & (65536 /* ReduceFlag */ >> 16)) == 0) { - let value = this.data[i + 1]; - if (!result.some((v, i) => (i & 1) && v == value)) - result.push(this.data[i], value); - } - } - return result; + } else { + var bytes = Buffer.isBuffer(val) + ? val + : Buffer.from(val, encoding) + var len = bytes.length + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') } - /// @internal - overrides(token, prev) { - let iPrev = findOffset(this.data, this.tokenPrecTable, prev); - return iPrev < 0 || findOffset(this.data, this.tokenPrecTable, token) < iPrev; + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] } - /// Configure the parser. Returns a new parser instance that has the - /// given settings modified. Settings not provided in `config` are - /// kept from the original parser. - configure(config) { - // Hideous reflection-based kludge to make it easy to create a - // slightly modified copy of a parser. - let copy = Object.assign(Object.create(LRParser.prototype), this); - if (config.props) - copy.nodeSet = this.nodeSet.extend(...config.props); - if (config.top) { - let info = this.topRules[config.top]; - if (!info) - throw new RangeError(`Invalid top rule name ${config.top}`); - copy.top = info; + } + + return this +} + +// HELPER FUNCTIONS +// ================ + +var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = str.trim().replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue } - if (config.tokenizers) - copy.tokenizers = this.tokenizers.map(t => { - let found = config.tokenizers.find(r => r.from == t); - return found ? found.to : t; - }); - if (config.contextTracker) - copy.context = config.contextTracker; - if (config.dialect) - copy.dialect = this.parseDialect(config.dialect); - if (config.strict != null) - copy.strict = config.strict; - if (config.wrap) - copy.wrappers = copy.wrappers.concat(config.wrap); - if (config.bufferLength != null) - copy.bufferLength = config.bufferLength; - return copy; - } - /// Returns the name associated with a given term. This will only - /// work for all terms when the parser was generated with the - /// `--names` option. By default, only the names of tagged terms are - /// stored. - getName(term) { - return this.termNames ? this.termNames[term] : String(term <= this.maxNode && this.nodeSet.types[term].name || term); - } - /// The eof term id is always allocated directly after the node - /// types. @internal - get eofTerm() { return this.maxNode + 1; } - /// The type of top node produced by the parser. - get topNode() { return this.nodeSet.types[this.top[1]]; } - /// @internal - dynamicPrecedence(term) { - let prec = this.dynamicPrecedences; - return prec == null ? 0 : prec[term] || 0; - } - /// @internal - parseDialect(dialect) { - let values = Object.keys(this.dialects), flags = values.map(() => false); - if (dialect) - for (let part of dialect.split(" ")) { - let id = values.indexOf(part); - if (id >= 0) - flags[id] = true; - } - let disabled = null; - for (let i = 0; i < values.length; i++) - if (!flags[i]) { - for (let j = this.dialects[values[i]], id; (id = this.data[j++]) != 65535 /* End */;) - (disabled || (disabled = new Uint8Array(this.maxTerm + 1)))[id] = 1; - } - return new Dialect(dialect, flags, disabled); + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) } - /// (used by the output of the parser generator) @internal - static deserialize(spec) { - return new LRParser(spec); + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') } + } + + return bytes } -function pair(data, off) { return data[off] | (data[off + 1] << 16); } -function findOffset(data, start, term) { - for (let i = start, next; (next = data[i]) != 65535 /* End */; i++) - if (next == term) - return i - start; - return -1; + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray } -function findFinished(stacks) { - let best = null; - for (let stack of stacks) { - let stopped = stack.p.stoppedAt; - if ((stack.pos == stack.p.stream.end || stopped != null && stack.pos > stopped) && - stack.p.parser.stateFlag(stack.state, 2 /* Accepting */) && - (!best || best.score < stack.score)) - best = stack; - } - return best; + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray } -exports.ContextTracker = ContextTracker; -exports.ExternalTokenizer = ExternalTokenizer; -exports.InputStream = InputStream; -exports.LRParser = LRParser; -exports.Stack = Stack; +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare +} -}).call(this,require('_process')) -},{"@lezer/common":55,"_process":135}],58:[function(require,module,exports){ +}).call(this)}).call(this,require("buffer").Buffer) +},{"base64-js":41,"buffer":44,"ieee754":90}],45:[function(require,module,exports){ var EventEmitter = require('events').EventEmitter var storage = require('./lib/storage') @@ -26508,7 +26802,7 @@ function expose (opts) { } } -},{"./lib/copy":59,"./lib/debug":60,"./lib/help":61,"./lib/log":62,"./lib/logger":63,"./lib/perf":64,"./lib/storage":65,"events":132,"wayfarer/get-all-routes":122}],59:[function(require,module,exports){ +},{"./lib/copy":46,"./lib/debug":47,"./lib/help":48,"./lib/log":49,"./lib/logger":50,"./lib/perf":51,"./lib/storage":52,"events":43,"wayfarer/get-all-routes":131}],46:[function(require,module,exports){ var stateCopy = require('state-copy') var pluck = require('plucker') @@ -26524,7 +26818,7 @@ function copy (state) { stateCopy(isStateString ? pluck.apply(this, arguments) : state) } -},{"plucker":111,"state-copy":119}],60:[function(require,module,exports){ +},{"plucker":119,"state-copy":128}],47:[function(require,module,exports){ /* eslint-disable node/no-deprecated-api */ var onChange = require('object-change-callsite') var nanologger = require('nanologger') @@ -26566,7 +26860,7 @@ function debug (state, emitter, app, localEmitter) { }) } -},{"assert":125,"nanologger":97,"object-change-callsite":107}],61:[function(require,module,exports){ +},{"assert":37,"nanologger":104,"object-change-callsite":115}],48:[function(require,module,exports){ module.exports = help function help () { @@ -26599,7 +26893,7 @@ function print (cmd, desc) { function noop () {} -},{}],62:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ var removeItems = require('remove-array-items') var scheduler = require('nanoscheduler')() var nanologger = require('nanologger') @@ -26677,7 +26971,7 @@ function log (state, emitter, app, localEmitter) { function noop () {} -},{"clone":74,"nanologger":97,"nanoscheduler":105,"remove-array-items":66}],63:[function(require,module,exports){ +},{"clone":61,"nanologger":104,"nanoscheduler":112,"remove-array-items":53}],50:[function(require,module,exports){ var scheduler = require('nanoscheduler')() var nanologger = require('nanologger') var Hooks = require('choo-hooks') @@ -26762,7 +27056,7 @@ function logger (state, emitter, opts) { } } -},{"choo-hooks":67,"nanologger":97,"nanoscheduler":105}],64:[function(require,module,exports){ +},{"choo-hooks":54,"nanologger":104,"nanoscheduler":112}],51:[function(require,module,exports){ var onPerformance = require('on-performance') var BAR = '█' @@ -26903,7 +27197,7 @@ function getMedian (args) { // Do nothing. function noop () {} -},{"on-performance":109}],65:[function(require,module,exports){ +},{"on-performance":117}],52:[function(require,module,exports){ var pretty = require('prettier-bytes') module.exports = storage @@ -26946,7 +27240,7 @@ function fmt (num) { function noop () {} -},{"prettier-bytes":112}],66:[function(require,module,exports){ +},{"prettier-bytes":120}],53:[function(require,module,exports){ 'use strict'; /** @@ -26977,7 +27271,7 @@ function removeItems (arr, startIdx, removeCount) { module.exports = removeItems; -},{}],67:[function(require,module,exports){ +},{}],54:[function(require,module,exports){ var onPerformance = require('on-performance') var scheduler = require('nanoscheduler')() var assert = require('assert') @@ -27106,7 +27400,7 @@ ChooHooks.prototype._emitLoaded = function () { }) } -},{"assert":125,"nanoscheduler":105,"on-performance":109}],68:[function(require,module,exports){ +},{"assert":37,"nanoscheduler":112,"on-performance":117}],55:[function(require,module,exports){ var assert = require('assert') var LRU = require('nanolru') @@ -27149,16 +27443,16 @@ function newCall (Cls) { return new (Cls.bind.apply(Cls, arguments)) // eslint-disable-line } -},{"assert":85,"nanolru":98}],69:[function(require,module,exports){ +},{"assert":93,"nanolru":105}],56:[function(require,module,exports){ module.exports = require('nanocomponent') -},{"nanocomponent":87}],70:[function(require,module,exports){ +},{"nanocomponent":95}],57:[function(require,module,exports){ module.exports = require('nanohtml') -},{"nanohtml":92}],71:[function(require,module,exports){ +},{"nanohtml":99}],58:[function(require,module,exports){ module.exports = require('nanohtml/raw') -},{"nanohtml/raw":95}],72:[function(require,module,exports){ +},{"nanohtml/raw":102}],59:[function(require,module,exports){ var scrollToAnchor = require('scroll-to-anchor') var documentReady = require('document-ready') var nanotiming = require('nanotiming') @@ -27442,7 +27736,7 @@ Choo.prototype._setCache = function (state) { } } -},{"./component/cache":68,"assert":85,"document-ready":75,"nanobus":86,"nanohref":89,"nanomorph":99,"nanoquery":102,"nanoraf":103,"nanorouter":104,"nanotiming":106,"scroll-to-anchor":118}],73:[function(require,module,exports){ +},{"./component/cache":55,"assert":93,"document-ready":62,"nanobus":94,"nanohref":96,"nanomorph":106,"nanoquery":109,"nanoraf":110,"nanorouter":111,"nanotiming":113,"scroll-to-anchor":127}],60:[function(require,module,exports){ /*! clipboard-copy. MIT License. Feross Aboukhadijeh */ /* global DOMException */ @@ -27495,8 +27789,8 @@ function clipboardCopy (text) { : Promise.reject(new DOMException('The request is not allowed', 'NotAllowedError')) } -},{}],74:[function(require,module,exports){ -(function (Buffer){ +},{}],61:[function(require,module,exports){ +(function (Buffer){(function (){ var clone = (function() { 'use strict'; @@ -27607,14211 +27901,13840 @@ function clone(parent, circular, depth, prototype, includeNonEnumerable) { // Node.js >= 4.5.0 child = Buffer.allocUnsafe(parent.length); } else { - // Older Node.js versions - child = new Buffer(parent.length); - } - parent.copy(child); - return child; - } else if (_instanceof(parent, Error)) { - child = Object.create(parent); - } else { - if (typeof prototype == 'undefined') { - proto = Object.getPrototypeOf(parent); - child = Object.create(proto); - } - else { - child = Object.create(prototype); - proto = prototype; - } - } - - if (circular) { - var index = allParents.indexOf(parent); - - if (index != -1) { - return allChildren[index]; - } - allParents.push(parent); - allChildren.push(child); - } - - if (_instanceof(parent, nativeMap)) { - parent.forEach(function(value, key) { - var keyChild = _clone(key, depth - 1); - var valueChild = _clone(value, depth - 1); - child.set(keyChild, valueChild); - }); - } - if (_instanceof(parent, nativeSet)) { - parent.forEach(function(value) { - var entryChild = _clone(value, depth - 1); - child.add(entryChild); - }); - } - - for (var i in parent) { - var attrs; - if (proto) { - attrs = Object.getOwnPropertyDescriptor(proto, i); - } - - if (attrs && attrs.set == null) { - continue; - } - child[i] = _clone(parent[i], depth - 1); - } - - if (Object.getOwnPropertySymbols) { - var symbols = Object.getOwnPropertySymbols(parent); - for (var i = 0; i < symbols.length; i++) { - // Don't need to worry about cloning a symbol because it is a primitive, - // like a number or string. - var symbol = symbols[i]; - var descriptor = Object.getOwnPropertyDescriptor(parent, symbol); - if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { - continue; - } - child[symbol] = _clone(parent[symbol], depth - 1); - if (!descriptor.enumerable) { - Object.defineProperty(child, symbol, { - enumerable: false - }); - } - } - } - - if (includeNonEnumerable) { - var allPropertyNames = Object.getOwnPropertyNames(parent); - for (var i = 0; i < allPropertyNames.length; i++) { - var propertyName = allPropertyNames[i]; - var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName); - if (descriptor && descriptor.enumerable) { - continue; - } - child[propertyName] = _clone(parent[propertyName], depth - 1); - Object.defineProperty(child, propertyName, { - enumerable: false - }); - } - } - - return child; - } - - return _clone(parent, depth); -} - -/** - * Simple flat clone using prototype, accepts only objects, usefull for property - * override on FLAT configuration object (no nested props). - * - * USE WITH CAUTION! This may not behave as you wish if you do not know how this - * works. - */ -clone.clonePrototype = function clonePrototype(parent) { - if (parent === null) - return null; - - var c = function () {}; - c.prototype = parent; - return new c(); -}; - -// private utility functions - -function __objToStr(o) { - return Object.prototype.toString.call(o); -} -clone.__objToStr = __objToStr; - -function __isDate(o) { - return typeof o === 'object' && __objToStr(o) === '[object Date]'; -} -clone.__isDate = __isDate; - -function __isArray(o) { - return typeof o === 'object' && __objToStr(o) === '[object Array]'; -} -clone.__isArray = __isArray; - -function __isRegExp(o) { - return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; -} -clone.__isRegExp = __isRegExp; - -function __getRegExpFlags(re) { - var flags = ''; - if (re.global) flags += 'g'; - if (re.ignoreCase) flags += 'i'; - if (re.multiline) flags += 'm'; - return flags; -} -clone.__getRegExpFlags = __getRegExpFlags; - -return clone; -})(); - -if (typeof module === 'object' && module.exports) { - module.exports = clone; -} - -}).call(this,require("buffer").Buffer) -},{"buffer":131}],75:[function(require,module,exports){ -'use strict' - -module.exports = ready - -function ready (callback) { - if (typeof document === 'undefined') { - throw new Error('document-ready only runs in the browser') - } - var state = document.readyState - if (state === 'complete' || state === 'interactive') { - return setTimeout(callback, 0) - } - - document.addEventListener('DOMContentLoaded', function onLoad () { - callback() - }) -} - -},{}],76:[function(require,module,exports){ -module.exports = stringify -stringify.default = stringify -stringify.stable = deterministicStringify -stringify.stableStringify = deterministicStringify - -var LIMIT_REPLACE_NODE = '[...]' -var CIRCULAR_REPLACE_NODE = '[Circular]' - -var arr = [] -var replacerStack = [] - -function defaultOptions () { - return { - depthLimit: Number.MAX_SAFE_INTEGER, - edgesLimit: Number.MAX_SAFE_INTEGER - } -} - -// Regular stringify -function stringify (obj, replacer, spacer, options) { - if (typeof options === 'undefined') { - options = defaultOptions() - } - - decirc(obj, '', 0, [], undefined, 0, options) - var res - try { - if (replacerStack.length === 0) { - res = JSON.stringify(obj, replacer, spacer) - } else { - res = JSON.stringify(obj, replaceGetterValues(replacer), spacer) - } - } catch (_) { - return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') - } finally { - while (arr.length !== 0) { - var part = arr.pop() - if (part.length === 4) { - Object.defineProperty(part[0], part[1], part[3]) - } else { - part[0][part[1]] = part[2] - } - } - } - return res -} - -function setReplace (replace, val, k, parent) { - var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k) - if (propertyDescriptor.get !== undefined) { - if (propertyDescriptor.configurable) { - Object.defineProperty(parent, k, { value: replace }) - arr.push([parent, k, val, propertyDescriptor]) - } else { - replacerStack.push([val, k, replace]) - } - } else { - parent[k] = replace - arr.push([parent, k, val]) - } -} - -function decirc (val, k, edgeIndex, stack, parent, depth, options) { - depth += 1 - var i - if (typeof val === 'object' && val !== null) { - for (i = 0; i < stack.length; i++) { - if (stack[i] === val) { - setReplace(CIRCULAR_REPLACE_NODE, val, k, parent) - return - } - } - - if ( - typeof options.depthLimit !== 'undefined' && - depth > options.depthLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent) - return - } - - if ( - typeof options.edgesLimit !== 'undefined' && - edgeIndex + 1 > options.edgesLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent) - return - } - - stack.push(val) - // Optimize for Arrays. Big arrays could kill the performance otherwise! - if (Array.isArray(val)) { - for (i = 0; i < val.length; i++) { - decirc(val[i], i, i, stack, val, depth, options) - } - } else { - var keys = Object.keys(val) - for (i = 0; i < keys.length; i++) { - var key = keys[i] - decirc(val[key], key, i, stack, val, depth, options) - } - } - stack.pop() - } -} - -// Stable-stringify -function compareFunction (a, b) { - if (a < b) { - return -1 - } - if (a > b) { - return 1 - } - return 0 -} - -function deterministicStringify (obj, replacer, spacer, options) { - if (typeof options === 'undefined') { - options = defaultOptions() - } - - var tmp = deterministicDecirc(obj, '', 0, [], undefined, 0, options) || obj - var res - try { - if (replacerStack.length === 0) { - res = JSON.stringify(tmp, replacer, spacer) - } else { - res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer) - } - } catch (_) { - return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') - } finally { - // Ensure that we restore the object as it was. - while (arr.length !== 0) { - var part = arr.pop() - if (part.length === 4) { - Object.defineProperty(part[0], part[1], part[3]) - } else { - part[0][part[1]] = part[2] - } - } - } - return res -} - -function deterministicDecirc (val, k, edgeIndex, stack, parent, depth, options) { - depth += 1 - var i - if (typeof val === 'object' && val !== null) { - for (i = 0; i < stack.length; i++) { - if (stack[i] === val) { - setReplace(CIRCULAR_REPLACE_NODE, val, k, parent) - return - } - } - try { - if (typeof val.toJSON === 'function') { - return - } - } catch (_) { - return - } - - if ( - typeof options.depthLimit !== 'undefined' && - depth > options.depthLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent) - return - } - - if ( - typeof options.edgesLimit !== 'undefined' && - edgeIndex + 1 > options.edgesLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent) - return - } - - stack.push(val) - // Optimize for Arrays. Big arrays could kill the performance otherwise! - if (Array.isArray(val)) { - for (i = 0; i < val.length; i++) { - deterministicDecirc(val[i], i, i, stack, val, depth, options) - } - } else { - // Create a temporary object in the required way - var tmp = {} - var keys = Object.keys(val).sort(compareFunction) - for (i = 0; i < keys.length; i++) { - var key = keys[i] - deterministicDecirc(val[key], key, i, stack, val, depth, options) - tmp[key] = val[key] - } - if (typeof parent !== 'undefined') { - arr.push([parent, k, val]) - parent[k] = tmp - } else { - return tmp - } - } - stack.pop() - } -} - -// wraps replacer function to handle values we couldn't replace -// and mark them as replaced value -function replaceGetterValues (replacer) { - replacer = - typeof replacer !== 'undefined' - ? replacer - : function (k, v) { - return v - } - return function (key, val) { - if (replacerStack.length > 0) { - for (var i = 0; i < replacerStack.length; i++) { - var part = replacerStack[i] - if (part[1] === key && part[0] === val) { - val = part[2] - replacerStack.splice(i, 1) - break - } - } - } - return replacer.call(this, key, val) - } -} - -},{}],77:[function(require,module,exports){ -(function (global){ -var topLevel = typeof global !== 'undefined' ? global : - typeof window !== 'undefined' ? window : {} -var minDoc = require('min-document'); - -var doccy; - -if (typeof document !== 'undefined') { - doccy = document; -} else { - doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; - - if (!doccy) { - doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; - } -} - -module.exports = doccy; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"min-document":130}],78:[function(require,module,exports){ -(function (global){ -var win; - -if (typeof window !== "undefined") { - win = window; -} else if (typeof global !== "undefined") { - win = global; -} else if (typeof self !== "undefined"){ - win = self; -} else { - win = {}; -} - -module.exports = win; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],79:[function(require,module,exports){ -module.exports = attributeToProperty - -var transform = { - 'class': 'className', - 'for': 'htmlFor', - 'http-equiv': 'httpEquiv' -} - -function attributeToProperty (h) { - return function (tagName, attrs, children) { - for (var attr in attrs) { - if (attr in transform) { - attrs[transform[attr]] = attrs[attr] - delete attrs[attr] - } - } - return h(tagName, attrs, children) - } -} - -},{}],80:[function(require,module,exports){ -var attrToProp = require('hyperscript-attribute-to-property') - -var VAR = 0, TEXT = 1, OPEN = 2, CLOSE = 3, ATTR = 4 -var ATTR_KEY = 5, ATTR_KEY_W = 6 -var ATTR_VALUE_W = 7, ATTR_VALUE = 8 -var ATTR_VALUE_SQ = 9, ATTR_VALUE_DQ = 10 -var ATTR_EQ = 11, ATTR_BREAK = 12 -var COMMENT = 13 - -module.exports = function (h, opts) { - if (!opts) opts = {} - var concat = opts.concat || function (a, b) { - return String(a) + String(b) - } - if (opts.attrToProp !== false) { - h = attrToProp(h) - } - - return function (strings) { - var state = TEXT, reg = '' - var arglen = arguments.length - var parts = [] - - for (var i = 0; i < strings.length; i++) { - if (i < arglen - 1) { - var arg = arguments[i+1] - var p = parse(strings[i]) - var xstate = state - if (xstate === ATTR_VALUE_DQ) xstate = ATTR_VALUE - if (xstate === ATTR_VALUE_SQ) xstate = ATTR_VALUE - if (xstate === ATTR_VALUE_W) xstate = ATTR_VALUE - if (xstate === ATTR) xstate = ATTR_KEY - if (xstate === OPEN) { - if (reg === '/') { - p.push([ OPEN, '/', arg ]) - reg = '' - } else { - p.push([ OPEN, arg ]) - } - } else if (xstate === COMMENT && opts.comments) { - reg += String(arg) - } else if (xstate !== COMMENT) { - p.push([ VAR, xstate, arg ]) - } - parts.push.apply(parts, p) - } else parts.push.apply(parts, parse(strings[i])) - } - - var tree = [null,{},[]] - var stack = [[tree,-1]] - for (var i = 0; i < parts.length; i++) { - var cur = stack[stack.length-1][0] - var p = parts[i], s = p[0] - if (s === OPEN && /^\//.test(p[1])) { - var ix = stack[stack.length-1][1] - if (stack.length > 1) { - stack.pop() - stack[stack.length-1][0][2][ix] = h( - cur[0], cur[1], cur[2].length ? cur[2] : undefined - ) - } - } else if (s === OPEN) { - var c = [p[1],{},[]] - cur[2].push(c) - stack.push([c,cur[2].length-1]) - } else if (s === ATTR_KEY || (s === VAR && p[1] === ATTR_KEY)) { - var key = '' - var copyKey - for (; i < parts.length; i++) { - if (parts[i][0] === ATTR_KEY) { - key = concat(key, parts[i][1]) - } else if (parts[i][0] === VAR && parts[i][1] === ATTR_KEY) { - if (typeof parts[i][2] === 'object' && !key) { - for (copyKey in parts[i][2]) { - if (parts[i][2].hasOwnProperty(copyKey) && !cur[1][copyKey]) { - cur[1][copyKey] = parts[i][2][copyKey] - } - } - } else { - key = concat(key, parts[i][2]) - } - } else break - } - if (parts[i][0] === ATTR_EQ) i++ - var j = i - for (; i < parts.length; i++) { - if (parts[i][0] === ATTR_VALUE || parts[i][0] === ATTR_KEY) { - if (!cur[1][key]) cur[1][key] = strfn(parts[i][1]) - else parts[i][1]==="" || (cur[1][key] = concat(cur[1][key], parts[i][1])); - } else if (parts[i][0] === VAR - && (parts[i][1] === ATTR_VALUE || parts[i][1] === ATTR_KEY)) { - if (!cur[1][key]) cur[1][key] = strfn(parts[i][2]) - else parts[i][2]==="" || (cur[1][key] = concat(cur[1][key], parts[i][2])); - } else { - if (key.length && !cur[1][key] && i === j - && (parts[i][0] === CLOSE || parts[i][0] === ATTR_BREAK)) { - // https://html.spec.whatwg.org/multipage/infrastructure.html#boolean-attributes - // empty string is falsy, not well behaved value in browser - cur[1][key] = key.toLowerCase() - } - if (parts[i][0] === CLOSE) { - i-- - } - break - } - } - } else if (s === ATTR_KEY) { - cur[1][p[1]] = true - } else if (s === VAR && p[1] === ATTR_KEY) { - cur[1][p[2]] = true - } else if (s === CLOSE) { - if (selfClosing(cur[0]) && stack.length) { - var ix = stack[stack.length-1][1] - stack.pop() - stack[stack.length-1][0][2][ix] = h( - cur[0], cur[1], cur[2].length ? cur[2] : undefined - ) - } - } else if (s === VAR && p[1] === TEXT) { - if (p[2] === undefined || p[2] === null) p[2] = '' - else if (!p[2]) p[2] = concat('', p[2]) - if (Array.isArray(p[2][0])) { - cur[2].push.apply(cur[2], p[2]) - } else { - cur[2].push(p[2]) - } - } else if (s === TEXT) { - cur[2].push(p[1]) - } else if (s === ATTR_EQ || s === ATTR_BREAK) { - // no-op - } else { - throw new Error('unhandled: ' + s) + // Older Node.js versions + child = new Buffer(parent.length); + } + parent.copy(child); + return child; + } else if (_instanceof(parent, Error)) { + child = Object.create(parent); + } else { + if (typeof prototype == 'undefined') { + proto = Object.getPrototypeOf(parent); + child = Object.create(proto); + } + else { + child = Object.create(prototype); + proto = prototype; } } - if (tree[2].length > 1 && /^\s*$/.test(tree[2][0])) { - tree[2].shift() + if (circular) { + var index = allParents.indexOf(parent); + + if (index != -1) { + return allChildren[index]; + } + allParents.push(parent); + allChildren.push(child); } - if (tree[2].length > 2 - || (tree[2].length === 2 && /\S/.test(tree[2][1]))) { - if (opts.createFragment) return opts.createFragment(tree[2]) - throw new Error( - 'multiple root elements must be wrapped in an enclosing tag' - ) + if (_instanceof(parent, nativeMap)) { + parent.forEach(function(value, key) { + var keyChild = _clone(key, depth - 1); + var valueChild = _clone(value, depth - 1); + child.set(keyChild, valueChild); + }); } - if (Array.isArray(tree[2][0]) && typeof tree[2][0][0] === 'string' - && Array.isArray(tree[2][0][2])) { - tree[2][0] = h(tree[2][0][0], tree[2][0][1], tree[2][0][2]) + if (_instanceof(parent, nativeSet)) { + parent.forEach(function(value) { + var entryChild = _clone(value, depth - 1); + child.add(entryChild); + }); } - return tree[2][0] - function parse (str) { - var res = [] - if (state === ATTR_VALUE_W) state = ATTR - for (var i = 0; i < str.length; i++) { - var c = str.charAt(i) - if (state === TEXT && c === '<') { - if (reg.length) res.push([TEXT, reg]) - reg = '' - state = OPEN - } else if (c === '>' && !quot(state) && state !== COMMENT) { - if (state === OPEN && reg.length) { - res.push([OPEN,reg]) - } else if (state === ATTR_KEY) { - res.push([ATTR_KEY,reg]) - } else if (state === ATTR_VALUE && reg.length) { - res.push([ATTR_VALUE,reg]) - } - res.push([CLOSE]) - reg = '' - state = TEXT - } else if (state === COMMENT && /-$/.test(reg) && c === '-') { - if (opts.comments) { - res.push([ATTR_VALUE,reg.substr(0, reg.length - 1)]) - } - reg = '' - state = TEXT - } else if (state === OPEN && /^!--$/.test(reg)) { - if (opts.comments) { - res.push([OPEN, reg],[ATTR_KEY,'comment'],[ATTR_EQ]) - } - reg = c - state = COMMENT - } else if (state === TEXT || state === COMMENT) { - reg += c - } else if (state === OPEN && c === '/' && reg.length) { - // no-op, self closing tag without a space
- } else if (state === OPEN && /\s/.test(c)) { - if (reg.length) { - res.push([OPEN, reg]) - } - reg = '' - state = ATTR - } else if (state === OPEN) { - reg += c - } else if (state === ATTR && /[^\s"'=/]/.test(c)) { - state = ATTR_KEY - reg = c - } else if (state === ATTR && /\s/.test(c)) { - if (reg.length) res.push([ATTR_KEY,reg]) - res.push([ATTR_BREAK]) - } else if (state === ATTR_KEY && /\s/.test(c)) { - res.push([ATTR_KEY,reg]) - reg = '' - state = ATTR_KEY_W - } else if (state === ATTR_KEY && c === '=') { - res.push([ATTR_KEY,reg],[ATTR_EQ]) - reg = '' - state = ATTR_VALUE_W - } else if (state === ATTR_KEY) { - reg += c - } else if ((state === ATTR_KEY_W || state === ATTR) && c === '=') { - res.push([ATTR_EQ]) - state = ATTR_VALUE_W - } else if ((state === ATTR_KEY_W || state === ATTR) && !/\s/.test(c)) { - res.push([ATTR_BREAK]) - if (/[\w-]/.test(c)) { - reg += c - state = ATTR_KEY - } else state = ATTR - } else if (state === ATTR_VALUE_W && c === '"') { - state = ATTR_VALUE_DQ - } else if (state === ATTR_VALUE_W && c === "'") { - state = ATTR_VALUE_SQ - } else if (state === ATTR_VALUE_DQ && c === '"') { - res.push([ATTR_VALUE,reg],[ATTR_BREAK]) - reg = '' - state = ATTR - } else if (state === ATTR_VALUE_SQ && c === "'") { - res.push([ATTR_VALUE,reg],[ATTR_BREAK]) - reg = '' - state = ATTR - } else if (state === ATTR_VALUE_W && !/\s/.test(c)) { - state = ATTR_VALUE - i-- - } else if (state === ATTR_VALUE && /\s/.test(c)) { - res.push([ATTR_VALUE,reg],[ATTR_BREAK]) - reg = '' - state = ATTR - } else if (state === ATTR_VALUE || state === ATTR_VALUE_SQ - || state === ATTR_VALUE_DQ) { - reg += c + for (var i in parent) { + var attrs; + if (proto) { + attrs = Object.getOwnPropertyDescriptor(proto, i); + } + + if (attrs && attrs.set == null) { + continue; + } + child[i] = _clone(parent[i], depth - 1); + } + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(parent); + for (var i = 0; i < symbols.length; i++) { + // Don't need to worry about cloning a symbol because it is a primitive, + // like a number or string. + var symbol = symbols[i]; + var descriptor = Object.getOwnPropertyDescriptor(parent, symbol); + if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { + continue; + } + child[symbol] = _clone(parent[symbol], depth - 1); + if (!descriptor.enumerable) { + Object.defineProperty(child, symbol, { + enumerable: false + }); } } - if (state === TEXT && reg.length) { - res.push([TEXT,reg]) - reg = '' - } else if (state === ATTR_VALUE && reg.length) { - res.push([ATTR_VALUE,reg]) - reg = '' - } else if (state === ATTR_VALUE_DQ && reg.length) { - res.push([ATTR_VALUE,reg]) - reg = '' - } else if (state === ATTR_VALUE_SQ && reg.length) { - res.push([ATTR_VALUE,reg]) - reg = '' - } else if (state === ATTR_KEY) { - res.push([ATTR_KEY,reg]) - reg = '' + } + + if (includeNonEnumerable) { + var allPropertyNames = Object.getOwnPropertyNames(parent); + for (var i = 0; i < allPropertyNames.length; i++) { + var propertyName = allPropertyNames[i]; + var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName); + if (descriptor && descriptor.enumerable) { + continue; + } + child[propertyName] = _clone(parent[propertyName], depth - 1); + Object.defineProperty(child, propertyName, { + enumerable: false + }); } - return res } - } - function strfn (x) { - if (typeof x === 'function') return x - else if (typeof x === 'string') return x - else if (x && typeof x === 'object') return x - else if (x === null || x === undefined) return x - else return concat('', x) + return child; } -} -function quot (state) { - return state === ATTR_VALUE_SQ || state === ATTR_VALUE_DQ + return _clone(parent, depth); } -var closeRE = RegExp('^(' + [ - 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command', 'embed', - 'frame', 'hr', 'img', 'input', 'isindex', 'keygen', 'link', 'meta', 'param', - 'source', 'track', 'wbr', '!--', - // SVG TAGS - 'animate', 'animateTransform', 'circle', 'cursor', 'desc', 'ellipse', - 'feBlend', 'feColorMatrix', 'feComposite', - 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', - 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', - 'feGaussianBlur', 'feImage', 'feMergeNode', 'feMorphology', - 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', - 'feTurbulence', 'font-face-format', 'font-face-name', 'font-face-uri', - 'glyph', 'glyphRef', 'hkern', 'image', 'line', 'missing-glyph', 'mpath', - 'path', 'polygon', 'polyline', 'rect', 'set', 'stop', 'tref', 'use', 'view', - 'vkern' -].join('|') + ')(?:[\.#][a-zA-Z0-9\u007F-\uFFFF_:-]+)*$') -function selfClosing (tag) { return closeRE.test(tag) } +/** + * Simple flat clone using prototype, accepts only objects, usefull for property + * override on FLAT configuration object (no nested props). + * + * USE WITH CAUTION! This may not behave as you wish if you do not know how this + * works. + */ +clone.clonePrototype = function clonePrototype(parent) { + if (parent === null) + return null; -},{"hyperscript-attribute-to-property":79}],81:[function(require,module,exports){ -'use strict'; + var c = function () {}; + c.prototype = parent; + return new c(); +}; -var _classCallCheck = require('@babel/runtime/helpers/classCallCheck'); -var _createClass = require('@babel/runtime/helpers/createClass'); +// private utility functions -function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } +function __objToStr(o) { + return Object.prototype.toString.call(o); +} +clone.__objToStr = __objToStr; -var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck); -var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass); +function __isDate(o) { + return typeof o === 'object' && __objToStr(o) === '[object Date]'; +} +clone.__isDate = __isDate; -var arr = []; -var each = arr.forEach; -var slice = arr.slice; -function defaults(obj) { - each.call(slice.call(arguments, 1), function (source) { - if (source) { - for (var prop in source) { - if (obj[prop] === undefined) obj[prop] = source[prop]; - } - } - }); - return obj; +function __isArray(o) { + return typeof o === 'object' && __objToStr(o) === '[object Array]'; } +clone.__isArray = __isArray; -// eslint-disable-next-line no-control-regex -var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; +function __isRegExp(o) { + return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; +} +clone.__isRegExp = __isRegExp; -var serializeCookie = function serializeCookie(name, val, options) { - var opt = options || {}; - opt.path = opt.path || '/'; - var value = encodeURIComponent(val); - var str = name + '=' + value; +function __getRegExpFlags(re) { + var flags = ''; + if (re.global) flags += 'g'; + if (re.ignoreCase) flags += 'i'; + if (re.multiline) flags += 'm'; + return flags; +} +clone.__getRegExpFlags = __getRegExpFlags; - if (opt.maxAge > 0) { - var maxAge = opt.maxAge - 0; - if (isNaN(maxAge)) throw new Error('maxAge should be a Number'); - str += '; Max-Age=' + Math.floor(maxAge); - } +return clone; +})(); - if (opt.domain) { - if (!fieldContentRegExp.test(opt.domain)) { - throw new TypeError('option domain is invalid'); - } +if (typeof module === 'object' && module.exports) { + module.exports = clone; +} - str += '; Domain=' + opt.domain; - } +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":44}],62:[function(require,module,exports){ +'use strict' - if (opt.path) { - if (!fieldContentRegExp.test(opt.path)) { - throw new TypeError('option path is invalid'); - } +module.exports = ready - str += '; Path=' + opt.path; +function ready (callback) { + if (typeof document === 'undefined') { + throw new Error('document-ready only runs in the browser') } - - if (opt.expires) { - if (typeof opt.expires.toUTCString !== 'function') { - throw new TypeError('option expires is invalid'); - } - - str += '; Expires=' + opt.expires.toUTCString(); + var state = document.readyState + if (state === 'complete' || state === 'interactive') { + return setTimeout(callback, 0) } - if (opt.httpOnly) str += '; HttpOnly'; - if (opt.secure) str += '; Secure'; - - if (opt.sameSite) { - var sameSite = typeof opt.sameSite === 'string' ? opt.sameSite.toLowerCase() : opt.sameSite; - - switch (sameSite) { - case true: - str += '; SameSite=Strict'; - break; - - case 'lax': - str += '; SameSite=Lax'; - break; + document.addEventListener('DOMContentLoaded', function onLoad () { + callback() + }) +} - case 'strict': - str += '; SameSite=Strict'; - break; +},{}],63:[function(require,module,exports){ +module.exports = stringify +stringify.default = stringify +stringify.stable = deterministicStringify +stringify.stableStringify = deterministicStringify - case 'none': - str += '; SameSite=None'; - break; +var arr = [] +var replacerStack = [] - default: - throw new TypeError('option sameSite is invalid'); +// Regular stringify +function stringify (obj, replacer, spacer) { + decirc(obj, '', [], undefined) + var res + if (replacerStack.length === 0) { + res = JSON.stringify(obj, replacer, spacer) + } else { + res = JSON.stringify(obj, replaceGetterValues(replacer), spacer) + } + while (arr.length !== 0) { + var part = arr.pop() + if (part.length === 4) { + Object.defineProperty(part[0], part[1], part[3]) + } else { + part[0][part[1]] = part[2] } } - - return str; -}; - -var cookie = { - create: function create(name, value, minutes, domain) { - var cookieOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : { - path: '/', - sameSite: 'strict' - }; - - if (minutes) { - cookieOptions.expires = new Date(); - cookieOptions.expires.setTime(cookieOptions.expires.getTime() + minutes * 60 * 1000); + return res +} +function decirc (val, k, stack, parent) { + var i + if (typeof val === 'object' && val !== null) { + for (i = 0; i < stack.length; i++) { + if (stack[i] === val) { + var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k) + if (propertyDescriptor.get !== undefined) { + if (propertyDescriptor.configurable) { + Object.defineProperty(parent, k, { value: '[Circular]' }) + arr.push([parent, k, val, propertyDescriptor]) + } else { + replacerStack.push([val, k]) + } + } else { + parent[k] = '[Circular]' + arr.push([parent, k, val]) + } + return + } } - - if (domain) cookieOptions.domain = domain; - document.cookie = serializeCookie(name, encodeURIComponent(value), cookieOptions); - }, - read: function read(name) { - var nameEQ = name + '='; - var ca = document.cookie.split(';'); - - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - - while (c.charAt(0) === ' ') { - c = c.substring(1, c.length); + stack.push(val) + // Optimize for Arrays. Big arrays could kill the performance otherwise! + if (Array.isArray(val)) { + for (i = 0; i < val.length; i++) { + decirc(val[i], i, stack, val) + } + } else { + var keys = Object.keys(val) + for (i = 0; i < keys.length; i++) { + var key = keys[i] + decirc(val[key], key, stack, val) } - - if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); } - - return null; - }, - remove: function remove(name) { - this.create(name, '', -1); + stack.pop() } -}; -var cookie$1 = { - name: 'cookie', - lookup: function lookup(options) { - var found; +} - if (options.lookupCookie && typeof document !== 'undefined') { - var c = cookie.read(options.lookupCookie); - if (c) found = c; - } +// Stable-stringify +function compareFunction (a, b) { + if (a < b) { + return -1 + } + if (a > b) { + return 1 + } + return 0 +} - return found; - }, - cacheUserLanguage: function cacheUserLanguage(lng, options) { - if (options.lookupCookie && typeof document !== 'undefined') { - cookie.create(options.lookupCookie, lng, options.cookieMinutes, options.cookieDomain, options.cookieOptions); +function deterministicStringify (obj, replacer, spacer) { + var tmp = deterministicDecirc(obj, '', [], undefined) || obj + var res + if (replacerStack.length === 0) { + res = JSON.stringify(tmp, replacer, spacer) + } else { + res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer) + } + while (arr.length !== 0) { + var part = arr.pop() + if (part.length === 4) { + Object.defineProperty(part[0], part[1], part[3]) + } else { + part[0][part[1]] = part[2] } } -}; - -var querystring = { - name: 'querystring', - lookup: function lookup(options) { - var found; - - if (typeof window !== 'undefined') { - var query = window.location.search.substring(1); - var params = query.split('&'); - - for (var i = 0; i < params.length; i++) { - var pos = params[i].indexOf('='); - - if (pos > 0) { - var key = params[i].substring(0, pos); + return res +} - if (key === options.lookupQuerystring) { - found = params[i].substring(pos + 1); +function deterministicDecirc (val, k, stack, parent) { + var i + if (typeof val === 'object' && val !== null) { + for (i = 0; i < stack.length; i++) { + if (stack[i] === val) { + var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k) + if (propertyDescriptor.get !== undefined) { + if (propertyDescriptor.configurable) { + Object.defineProperty(parent, k, { value: '[Circular]' }) + arr.push([parent, k, val, propertyDescriptor]) + } else { + replacerStack.push([val, k]) } + } else { + parent[k] = '[Circular]' + arr.push([parent, k, val]) } + return + } + } + if (typeof val.toJSON === 'function') { + return + } + stack.push(val) + // Optimize for Arrays. Big arrays could kill the performance otherwise! + if (Array.isArray(val)) { + for (i = 0; i < val.length; i++) { + deterministicDecirc(val[i], i, stack, val) + } + } else { + // Create a temporary object in the required way + var tmp = {} + var keys = Object.keys(val).sort(compareFunction) + for (i = 0; i < keys.length; i++) { + var key = keys[i] + deterministicDecirc(val[key], key, stack, val) + tmp[key] = val[key] + } + if (parent !== undefined) { + arr.push([parent, k, val]) + parent[k] = tmp + } else { + return tmp } } + stack.pop() + } +} - return found; +// wraps replacer function to handle values we couldn't replace +// and mark them as [Circular] +function replaceGetterValues (replacer) { + replacer = replacer !== undefined ? replacer : function (k, v) { return v } + return function (key, val) { + if (replacerStack.length > 0) { + for (var i = 0; i < replacerStack.length; i++) { + var part = replacerStack[i] + if (part[1] === key && part[0] === val) { + val = '[Circular]' + replacerStack.splice(i, 1) + break + } + } + } + return replacer.call(this, key, val) } -}; +} -var hasLocalStorageSupport = null; +},{}],64:[function(require,module,exports){ +(function (global){(function (){ +var topLevel = typeof global !== 'undefined' ? global : + typeof window !== 'undefined' ? window : {} +var minDoc = require('min-document'); -var localStorageAvailable = function localStorageAvailable() { - if (hasLocalStorageSupport !== null) return hasLocalStorageSupport; +var doccy; - try { - hasLocalStorageSupport = window !== 'undefined' && window.localStorage !== null; - var testKey = 'i18next.translate.boo'; - window.localStorage.setItem(testKey, 'foo'); - window.localStorage.removeItem(testKey); - } catch (e) { - hasLocalStorageSupport = false; - } +if (typeof document !== 'undefined') { + doccy = document; +} else { + doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; - return hasLocalStorageSupport; -}; + if (!doccy) { + doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; + } +} -var localStorage = { - name: 'localStorage', - lookup: function lookup(options) { - var found; +module.exports = doccy; - if (options.lookupLocalStorage && localStorageAvailable()) { - var lng = window.localStorage.getItem(options.lookupLocalStorage); - if (lng) found = lng; - } +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"min-document":42}],65:[function(require,module,exports){ +(function (global){(function (){ +var win; - return found; - }, - cacheUserLanguage: function cacheUserLanguage(lng, options) { - if (options.lookupLocalStorage && localStorageAvailable()) { - window.localStorage.setItem(options.lookupLocalStorage, lng); - } - } -}; +if (typeof window !== "undefined") { + win = window; +} else if (typeof global !== "undefined") { + win = global; +} else if (typeof self !== "undefined"){ + win = self; +} else { + win = {}; +} -var hasSessionStorageSupport = null; +module.exports = win; -var sessionStorageAvailable = function sessionStorageAvailable() { - if (hasSessionStorageSupport !== null) return hasSessionStorageSupport; +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],66:[function(require,module,exports){ +const Output = require('./src/output.js') +const loop = require('raf-loop') +const Source = require('./src/hydra-source.js') +const Mouse = require('./src/lib/mouse.js')() +const Audio = require('./src/lib/audio.js') +const VidRecorder = require('./src/lib/video-recorder.js') +const ArrayUtils = require('./src/lib/array-utils.js') +const Sandbox = require('./src/eval-sandbox.js') - try { - hasSessionStorageSupport = window !== 'undefined' && window.sessionStorage !== null; - var testKey = 'i18next.translate.boo'; - window.sessionStorage.setItem(testKey, 'foo'); - window.sessionStorage.removeItem(testKey); - } catch (e) { - hasSessionStorageSupport = false; - } +const Generator = require('./src/generator-factory.js') - return hasSessionStorageSupport; -}; +// to do: add ability to pass in certain uniforms and transforms +class HydraRenderer { -var sessionStorage = { - name: 'sessionStorage', - lookup: function lookup(options) { - var found; + constructor ({ + pb = null, + width = 1280, + height = 720, + numSources = 4, + numOutputs = 4, + makeGlobal = true, + autoLoop = true, + detectAudio = true, + enableStreamCapture = true, + canvas, + precision, + extendTransforms = {} // add your own functions on init + } = {}) { - if (options.lookupSessionStorage && sessionStorageAvailable()) { - var lng = window.sessionStorage.getItem(options.lookupSessionStorage); - if (lng) found = lng; - } + ArrayUtils.init() - return found; - }, - cacheUserLanguage: function cacheUserLanguage(lng, options) { - if (options.lookupSessionStorage && sessionStorageAvailable()) { - window.sessionStorage.setItem(options.lookupSessionStorage, lng); - } - } -}; + this.pb = pb -var navigator$1 = { - name: 'navigator', - lookup: function lookup(options) { - var found = []; + this.width = width + this.height = height + this.renderAll = false + this.detectAudio = detectAudio - if (typeof navigator !== 'undefined') { - if (navigator.languages) { - // chrome only; not an array, so can't use .push.apply instead of iterating - for (var i = 0; i < navigator.languages.length; i++) { - found.push(navigator.languages[i]); - } - } + this._initCanvas(canvas) - if (navigator.userLanguage) { - found.push(navigator.userLanguage); - } - if (navigator.language) { - found.push(navigator.language); - } + // object that contains all properties that will be made available on the global context and during local evaluation + this.synth = { + time: 0, + bpm: 30, + width: this.width, + height: this.height, + fps: undefined, + stats: { + fps: 0 + }, + speed: 1, + mouse: Mouse, + render: this._render.bind(this), + setResolution: this.setResolution.bind(this), + update: (dt) => {},// user defined update function + hush: this.hush.bind(this) } - return found.length > 0 ? found : undefined; - } -}; + if (makeGlobal) window.loadScript = this.loadScript -var htmlTag = { - name: 'htmlTag', - lookup: function lookup(options) { - var found; - var htmlTag = options.htmlTag || (typeof document !== 'undefined' ? document.documentElement : null); - if (htmlTag && typeof htmlTag.getAttribute === 'function') { - found = htmlTag.getAttribute('lang'); + this.timeSinceLastUpdate = 0 + this._time = 0 // for internal use, only to use for deciding when to render frames + + // only allow valid precision options + let precisionOptions = ['lowp','mediump','highp'] + if(precision && precisionOptions.includes(precision.toLowerCase())) { + this.precision = precision.toLowerCase() + // + // if(!precisionValid){ + // console.warn('[hydra-synth warning]\nConstructor was provided an invalid floating point precision value of "' + precision + '". Using default value of "mediump" instead.') + // } + } else { + let isIOS = + (/iPad|iPhone|iPod/.test(navigator.platform) || + (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) && + !window.MSStream; + this.precision = isIOS ? 'highp' : 'mediump' } - return found; - } -}; -var path = { - name: 'path', - lookup: function lookup(options) { - var found; - if (typeof window !== 'undefined') { - var language = window.location.pathname.match(/\/([a-zA-Z-]*)/g); + this.extendTransforms = extendTransforms - if (language instanceof Array) { - if (typeof options.lookupFromPathIndex === 'number') { - if (typeof language[options.lookupFromPathIndex] !== 'string') { - return undefined; - } + // boolean to store when to save screenshot + this.saveFrame = false - found = language[options.lookupFromPathIndex].replace('/', ''); - } else { - found = language[0].replace('/', ''); - } - } - } + // if stream capture is enabled, this object contains the capture stream + this.captureStream = null - return found; - } -}; + this.generator = undefined -var subdomain = { - name: 'subdomain', - lookup: function lookup(options) { - var found; + this._initRegl() + this._initOutputs(numOutputs) + this._initSources(numSources) + this._generateGlslTransforms() - if (typeof window !== 'undefined') { - var language = window.location.href.match(/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/gi); + this.synth.screencap = () => { + this.saveFrame = true + } - if (language instanceof Array) { - if (typeof options.lookupFromSubdomainIndex === 'number') { - found = language[options.lookupFromSubdomainIndex].replace('http://', '').replace('https://', '').replace('.', ''); - } else { - found = language[0].replace('http://', '').replace('https://', '').replace('.', ''); - } + if (enableStreamCapture) { + try { + this.captureStream = this.canvas.captureStream(25) + // to do: enable capture stream of specific sources and outputs + this.synth.vidRecorder = new VidRecorder(this.captureStream) + } catch (e) { + console.warn('[hydra-synth warning]\nnew MediaSource() is not currently supported on iOS.') + console.error(e) } } - return found; - } -}; + if(detectAudio) this._initAudio() -function getDefaults() { - return { - order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag'], - lookupQuerystring: 'lng', - lookupCookie: 'i18next', - lookupLocalStorage: 'i18nextLng', - lookupSessionStorage: 'i18nextLng', - // cache user language - caches: ['localStorage'], - excludeCacheFor: ['cimode'] //cookieMinutes: 10, - //cookieDomain: 'myDomain' + if(autoLoop) loop(this.tick.bind(this)).start() - }; -} + // final argument is properties that the user can set, all others are treated as read-only + this.sandbox = new Sandbox(this.synth, makeGlobal, ['speed', 'update', 'bpm', 'fps']) + } -var Browser = /*#__PURE__*/function () { - function Browser(services) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + eval(code) { + this.sandbox.eval(code) + } - _classCallCheck__default["default"](this, Browser); + getScreenImage(callback) { + this.imageCallback = callback + this.saveFrame = true + } - this.type = 'languageDetector'; - this.detectors = {}; - this.init(services, options); + hush() { + this.s.forEach((source) => { + source.clear() + }) + this.o.forEach((output) => { + this.synth.solid(1, 1, 1, 0).out(output) + }) } - _createClass__default["default"](Browser, [{ - key: "init", - value: function init(services) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var i18nOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - this.services = services; - this.options = defaults(options, this.options || {}, getDefaults()); // backwards compatibility + loadScript(url = "") { + const p = new Promise((res, rej) => { + var script = document.createElement("script"); + script.onload = function () { + console.log(`loaded script ${url}`); + res(); + }; + script.onerror = (err) => { + console.log(`error loading script ${url}`, "log-error"); + res() + }; + script.src = url; + document.head.appendChild(script); + }); + return p; + } - if (this.options.lookupFromUrlIndex) this.options.lookupFromPathIndex = this.options.lookupFromUrlIndex; - this.i18nOptions = i18nOptions; - this.addDetector(cookie$1); - this.addDetector(querystring); - this.addDetector(localStorage); - this.addDetector(sessionStorage); - this.addDetector(navigator$1); - this.addDetector(htmlTag); - this.addDetector(path); - this.addDetector(subdomain); - } - }, { - key: "addDetector", - value: function addDetector(detector) { - this.detectors[detector.name] = detector; - } - }, { - key: "detect", - value: function detect(detectionOrder) { - var _this = this; + setResolution(width, height) { + // console.log(width, height) + this.canvas.width = width + this.canvas.height = height + this.width = width + this.height = height + this.o.forEach((output) => { + output.resize(width, height) + }) + this.s.forEach((source) => { + source.resize(width, height) + }) + this.regl._refresh() + console.log(this.canvas.width) + } - if (!detectionOrder) detectionOrder = this.options.order; - var detected = []; - detectionOrder.forEach(function (detectorName) { - if (_this.detectors[detectorName]) { - var lookup = _this.detectors[detectorName].lookup(_this.options); + canvasToImage (callback) { + const a = document.createElement('a') + a.style.display = 'none' - if (lookup && typeof lookup === 'string') lookup = [lookup]; - if (lookup) detected = detected.concat(lookup); + let d = new Date() + a.download = `hydra-${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}-${d.getHours()}.${d.getMinutes()}.${d.getSeconds()}.png` + document.body.appendChild(a) + var self = this + this.canvas.toBlob( (blob) => { + if(self.imageCallback){ + self.imageCallback(blob) + delete self.imageCallback + } else { + a.href = URL.createObjectURL(blob) + console.log(a.href) + a.click() } - }); - if (this.services.languageUtils.getBestMatchFromCodes) return detected; // new i18next v19.5.0 + }, 'image/png') + setTimeout(() => { + document.body.removeChild(a); + window.URL.revokeObjectURL(a.href); + }, 300); + } - return detected.length > 0 ? detected[0] : null; // a little backward compatibility - } - }, { - key: "cacheUserLanguage", - value: function cacheUserLanguage(lng, caches) { - var _this2 = this; + _initAudio () { + const that = this + this.synth.a = new Audio({ + numBins: 4, + // changeListener: ({audio}) => { + // that.a = audio.bins.map((_, index) => + // (scale = 1, offset = 0) => () => (audio.fft[index] * scale + offset) + // ) + // + // if (that.makeGlobal) { + // that.a.forEach((a, index) => { + // const aname = `a${index}` + // window[aname] = a + // }) + // } + // } + }) + } - if (!caches) caches = this.options.caches; - if (!caches) return; - if (this.options.excludeCacheFor && this.options.excludeCacheFor.indexOf(lng) > -1) return; - caches.forEach(function (cacheName) { - if (_this2.detectors[cacheName]) _this2.detectors[cacheName].cacheUserLanguage(lng, _this2.options); - }); + // create main output canvas and add to screen + _initCanvas (canvas) { + if (canvas) { + this.canvas = canvas + this.width = canvas.width + this.height = canvas.height + } else { + this.canvas = document.createElement('canvas') + this.canvas.width = this.width + this.canvas.height = this.height + this.canvas.style.width = '100%' + this.canvas.style.height = '100%' + this.canvas.style.imageRendering = 'pixelated' + document.body.appendChild(this.canvas) } - }]); + } - return Browser; -}(); + _initRegl () { + this.regl = require('regl')({ + // profile: true, + canvas: this.canvas, + pixelRatio: 1//, + // extensions: [ + // 'oes_texture_half_float', + // 'oes_texture_half_float_linear' + // ], + // optionalExtensions: [ + // 'oes_texture_float', + // 'oes_texture_float_linear' + //] + }) -Browser.type = 'languageDetector'; + // This clears the color buffer to black and the depth buffer to 1 + this.regl.clear({ + color: [0, 0, 0, 1] + }) -module.exports = Browser; + this.renderAll = this.regl({ + frag: ` + precision ${this.precision} float; + varying vec2 uv; + uniform sampler2D tex0; + uniform sampler2D tex1; + uniform sampler2D tex2; + uniform sampler2D tex3; -},{"@babel/runtime/helpers/classCallCheck":32,"@babel/runtime/helpers/createClass":33}],82:[function(require,module,exports){ -'use strict'; + void main () { + vec2 st = vec2(1.0 - uv.x, uv.y); + st*= vec2(2); + vec2 q = floor(st).xy*(vec2(2.0, 1.0)); + int quad = int(q.x) + int(q.y); + st.x += step(1., mod(st.y,2.0)); + st.y += step(1., mod(st.x,2.0)); + st = fract(st); + if(quad==0){ + gl_FragColor = texture2D(tex0, st); + } else if(quad==1){ + gl_FragColor = texture2D(tex1, st); + } else if (quad==2){ + gl_FragColor = texture2D(tex2, st); + } else { + gl_FragColor = texture2D(tex3, st); + } -var _typeof = require('@babel/runtime/helpers/typeof'); -var _classCallCheck = require('@babel/runtime/helpers/classCallCheck'); -var _createClass = require('@babel/runtime/helpers/createClass'); -var _assertThisInitialized = require('@babel/runtime/helpers/assertThisInitialized'); -var _inherits = require('@babel/runtime/helpers/inherits'); -var _possibleConstructorReturn = require('@babel/runtime/helpers/possibleConstructorReturn'); -var _getPrototypeOf = require('@babel/runtime/helpers/getPrototypeOf'); -var _defineProperty = require('@babel/runtime/helpers/defineProperty'); -var _toArray = require('@babel/runtime/helpers/toArray'); + } + `, + vert: ` + precision ${this.precision} float; + attribute vec2 position; + varying vec2 uv; -function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } + void main () { + uv = position; + gl_Position = vec4(1.0 - 2.0 * position, 0, 1); + }`, + attributes: { + position: [ + [-2, 0], + [0, -2], + [2, 2] + ] + }, + uniforms: { + tex0: this.regl.prop('tex0'), + tex1: this.regl.prop('tex1'), + tex2: this.regl.prop('tex2'), + tex3: this.regl.prop('tex3') + }, + count: 3, + depth: { enable: false } + }) -var _typeof__default = /*#__PURE__*/_interopDefaultLegacy(_typeof); -var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck); -var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass); -var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized); -var _inherits__default = /*#__PURE__*/_interopDefaultLegacy(_inherits); -var _possibleConstructorReturn__default = /*#__PURE__*/_interopDefaultLegacy(_possibleConstructorReturn); -var _getPrototypeOf__default = /*#__PURE__*/_interopDefaultLegacy(_getPrototypeOf); -var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty); -var _toArray__default = /*#__PURE__*/_interopDefaultLegacy(_toArray); + this.renderFbo = this.regl({ + frag: ` + precision ${this.precision} float; + varying vec2 uv; + uniform vec2 resolution; + uniform sampler2D tex0; + + void main () { + gl_FragColor = texture2D(tex0, vec2(1.0 - uv.x, uv.y)); + } + `, + vert: ` + precision ${this.precision} float; + attribute vec2 position; + varying vec2 uv; -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } + void main () { + uv = position; + gl_Position = vec4(1.0 - 2.0 * position, 0, 1); + }`, + attributes: { + position: [ + [-2, 0], + [0, -2], + [2, 2] + ] + }, + uniforms: { + tex0: this.regl.prop('tex0'), + resolution: this.regl.prop('resolution') + }, + count: 3, + depth: { enable: false } + }) + } -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + _initOutputs (numOutputs) { + const self = this + this.o = (Array(numOutputs)).fill().map((el, index) => { + var o = new Output({ + regl: this.regl, + width: this.width, + height: this.height, + precision: this.precision, + label: `o${index}` + }) + // o.render() + o.id = index + self.synth['o'+index] = o + return o + }) -var consoleLogger = { - type: 'logger', - log: function log(args) { - this.output('log', args); - }, - warn: function warn(args) { - this.output('warn', args); - }, - error: function error(args) { - this.output('error', args); - }, - output: function output(type, args) { - if (console && console[type]) console[type].apply(console, args); + // set default output + this.output = this.o[0] } -}; - -var Logger = function () { - function Logger(concreteLogger) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - _classCallCheck__default['default'](this, Logger); + _initSources (numSources) { + this.s = [] + for(var i = 0; i < numSources; i++) { + this.createSource(i) + } + } - this.init(concreteLogger, options); + createSource (i) { + let s = new Source({regl: this.regl, pb: this.pb, width: this.width, height: this.height, label: `s${i}`}) + this.synth['s' + this.s.length] = s + this.s.push(s) + return s } - _createClass__default['default'](Logger, [{ - key: "init", - value: function init(concreteLogger) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - this.prefix = options.prefix || 'i18next:'; - this.logger = concreteLogger || consoleLogger; - this.options = options; - this.debug = options.debug; - } - }, { - key: "setDebug", - value: function setDebug(bool) { - this.debug = bool; - } - }, { - key: "log", - value: function log() { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; + _generateGlslTransforms () { + var self = this + this.generator = new Generator({ + defaultOutput: this.o[0], + defaultUniforms: this.o[0].uniforms, + extendTransforms: this.extendTransforms, + changeListener: ({type, method, synth}) => { + if (type === 'add') { + self.synth[method] = synth.generators[method] + if(self.sandbox) self.sandbox.add(method) + } else if (type === 'remove') { + // what to do here? dangerously deleting window methods + //delete window[method] + } + // } } + }) + this.synth.setFunction = this.generator.setFunction.bind(this.generator) + } - return this.forward(args, 'log', '', true); + _render (output) { + if (output) { + this.output = output + this.isRenderingAll = false + } else { + this.isRenderingAll = true } - }, { - key: "warn", - value: function warn() { - for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } + } - return this.forward(args, 'warn', '', true); + // dt in ms + tick (dt, uniforms) { + this.sandbox.tick() + if(this.detectAudio === true) this.synth.a.tick() + // let updateInterval = 1000/this.synth.fps // ms + if(this.synth.update) { + try { this.synth.update(dt) } catch (e) { console.log(error) } } - }, { - key: "error", - value: function error() { - for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; - } - return this.forward(args, 'error', ''); - } - }, { - key: "deprecate", - value: function deprecate() { - for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - args[_key4] = arguments[_key4]; + this.sandbox.set('time', this.synth.time += dt * 0.001 * this.synth.speed) + this.timeSinceLastUpdate += dt + if(!this.synth.fps || this.timeSinceLastUpdate >= 1000/this.synth.fps) { + // console.log(1000/this.timeSinceLastUpdate) + this.synth.stats.fps = Math.ceil(1000/this.timeSinceLastUpdate) + // console.log(this.synth.speed, this.synth.time) + for (let i = 0; i < this.s.length; i++) { + this.s[i].tick(this.synth.time) + } + // console.log(this.canvas.width, this.canvas.height) + for (let i = 0; i < this.o.length; i++) { + this.o[i].tick({ + time: this.synth.time, + mouse: this.synth.mouse, + bpm: this.synth.bpm, + resolution: [this.canvas.width, this.canvas.height] + }) } + if (this.isRenderingAll) { + this.renderAll({ + tex0: this.o[0].getCurrent(), + tex1: this.o[1].getCurrent(), + tex2: this.o[2].getCurrent(), + tex3: this.o[3].getCurrent(), + resolution: [this.canvas.width, this.canvas.height] + }) + } else { - return this.forward(args, 'warn', 'WARNING DEPRECATED: ', true); - } - }, { - key: "forward", - value: function forward(args, lvl, prefix, debugOnly) { - if (debugOnly && !this.debug) return null; - if (typeof args[0] === 'string') args[0] = "".concat(prefix).concat(this.prefix, " ").concat(args[0]); - return this.logger[lvl](args); + this.renderFbo({ + tex0: this.output.getCurrent(), + resolution: [this.canvas.width, this.canvas.height] + }) + } + this.timeSinceLastUpdate = 0 } - }, { - key: "create", - value: function create(moduleName) { - return new Logger(this.logger, _objectSpread(_objectSpread({}, { - prefix: "".concat(this.prefix, ":").concat(moduleName, ":") - }), this.options)); + if(this.saveFrame === true) { + this.canvasToImage() + this.saveFrame = false } - }]); - - return Logger; -}(); + // this.regl.poll() + } -var baseLogger = new Logger(); -var EventEmitter = function () { - function EventEmitter() { - _classCallCheck__default['default'](this, EventEmitter); +} - this.observers = {}; - } +module.exports = HydraRenderer - _createClass__default['default'](EventEmitter, [{ - key: "on", - value: function on(events, listener) { - var _this = this; +},{"./src/eval-sandbox.js":68,"./src/generator-factory.js":71,"./src/hydra-source.js":75,"./src/lib/array-utils.js":76,"./src/lib/audio.js":77,"./src/lib/mouse.js":80,"./src/lib/video-recorder.js":83,"./src/output.js":85,"raf-loop":122,"regl":124}],67:[function(require,module,exports){ +const Synth = require('./hydra-synth.js') +//const ShaderGenerator = require('./shader-generator.js') - events.split(' ').forEach(function (event) { - _this.observers[event] = _this.observers[event] || []; +module.exports = Synth - _this.observers[event].push(listener); - }); - return this; - } - }, { - key: "off", - value: function off(event, listener) { - if (!this.observers[event]) return; +},{"./hydra-synth.js":66}],68:[function(require,module,exports){ +// handles code evaluation and attaching relevant objects to global and evaluation contexts - if (!listener) { - delete this.observers[event]; - return; - } +const Sandbox = require('./lib/sandbox.js') +const ArrayUtils = require('./lib/array-utils.js') - this.observers[event] = this.observers[event].filter(function (l) { - return l !== listener; - }); - } - }, { - key: "emit", - value: function emit(event) { - for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } +class EvalSandbox { + constructor(parent, makeGlobal, userProps = []) { + this.makeGlobal = makeGlobal + this.sandbox = Sandbox(parent) + this.parent = parent + var properties = Object.keys(parent) + properties.forEach((property) => this.add(property)) + this.userProps = userProps + } - if (this.observers[event]) { - var cloned = [].concat(this.observers[event]); - cloned.forEach(function (observer) { - observer.apply(void 0, args); - }); - } + add(name) { + if(this.makeGlobal) window[name] = this.parent[name] + this.sandbox.addToContext(name, `parent.${name}`) + } - if (this.observers['*']) { - var _cloned = [].concat(this.observers['*']); +// sets on window as well as synth object if global (not needed for objects, which can be set directly) - _cloned.forEach(function (observer) { - observer.apply(observer, [event].concat(args)); - }); - } + set(property, value) { + if(this.makeGlobal) { + window[property] = value } - }]); - - return EventEmitter; -}(); + this.parent[property] = value + } -function defer() { - var res; - var rej; - var promise = new Promise(function (resolve, reject) { - res = resolve; - rej = reject; - }); - promise.resolve = res; - promise.reject = rej; - return promise; -} -function makeString(object) { - if (object == null) return ''; - return '' + object; -} -function copy(a, s, t) { - a.forEach(function (m) { - if (s[m]) t[m] = s[m]; - }); -} + tick() { + if(this.makeGlobal) { + this.userProps.forEach((property) => { + this.parent[property] = window[property] + }) + // this.parent.speed = window.speed + } else { -function getLastOfPath(object, path, Empty) { - function cleanKey(key) { - return key && key.indexOf('###') > -1 ? key.replace(/###/g, '.') : key; + } } - function canNotTraverseDeeper() { - return !object || typeof object === 'string'; + eval(code) { + this.sandbox.eval(code) } +} - var stack = typeof path !== 'string' ? [].concat(path) : path.split('.'); +module.exports = EvalSandbox - while (stack.length > 1) { - if (canNotTraverseDeeper()) return {}; - var key = cleanKey(stack.shift()); - if (!object[key] && Empty) object[key] = new Empty(); +},{"./lib/array-utils.js":76,"./lib/sandbox.js":81}],69:[function(require,module,exports){ +const arrayUtils = require('./lib/array-utils.js') - if (Object.prototype.hasOwnProperty.call(object, key)) { - object = object[key]; +// [WIP] how to treat different dimensions (?) +const DEFAULT_CONVERSIONS = { + float: { + 'vec4': { name: 'sum', args: [[1, 1, 1, 1]] }, + 'vec2': { name: 'sum', args: [[1, 1]] } + } +} + +function fillArrayWithDefaults(arr, len) { + // fill the array with default values if it's too short + while (arr.length < len) { + if (arr.length === 3) { // push a 1 as the default for .a in vec4 + arr.push(1.0) } else { - object = {}; + arr.push(0.0) } } + return arr.slice(0, len) +} - if (canNotTraverseDeeper()) return {}; - return { - obj: object, - k: cleanKey(stack.shift()) - }; +const ensure_decimal_dot = (val) => { + val = val.toString() + if (val.indexOf('.') < 0) { + val += '.' + } + return val } -function setPath(object, path, newValue) { - var _getLastOfPath = getLastOfPath(object, path, Object), - obj = _getLastOfPath.obj, - k = _getLastOfPath.k; - obj[k] = newValue; -} -function pushPath(object, path, newValue, concat) { - var _getLastOfPath2 = getLastOfPath(object, path, Object), - obj = _getLastOfPath2.obj, - k = _getLastOfPath2.k; - obj[k] = obj[k] || []; - if (concat) obj[k] = obj[k].concat(newValue); - if (!concat) obj[k].push(newValue); -} -function getPath(object, path) { - var _getLastOfPath3 = getLastOfPath(object, path), - obj = _getLastOfPath3.obj, - k = _getLastOfPath3.k; +module.exports = function formatArguments(transform, startIndex, synthContext) { + const defaultArgs = transform.transform.inputs + const userArgs = transform.userArgs + const { generators } = transform.synth + const { src } = generators // depends on synth having src() function + return defaultArgs.map((input, index) => { + const typedArg = { + value: input.default, + type: input.type, // + isUniform: false, + name: input.name, + vecLen: 0 + // generateGlsl: null // function for creating glsl + } - if (!obj) return undefined; - return obj[k]; -} -function getPathWithDefaults(data, defaultData, key) { - var value = getPath(data, key); + if (typedArg.type === 'float') typedArg.value = ensure_decimal_dot(input.default) + if (input.type.startsWith('vec')) { + try { + typedArg.vecLen = Number.parseInt(input.type.substr(3)) + } catch (e) { + console.log(`Error determining length of vector input type ${input.type} (${input.name})`) + } + } - if (value !== undefined) { - return value; - } + // if user has input something for this argument + if (userArgs.length > index) { + typedArg.value = userArgs[index] + // do something if a composite or transform - return getPath(defaultData, key); -} -function deepExtend(target, source, overwrite) { - for (var prop in source) { - if (prop !== '__proto__' && prop !== 'constructor') { - if (prop in target) { - if (typeof target[prop] === 'string' || target[prop] instanceof String || typeof source[prop] === 'string' || source[prop] instanceof String) { - if (overwrite) target[prop] = source[prop]; - } else { - deepExtend(target[prop], source[prop], overwrite); + if (typeof userArgs[index] === 'function') { + // if (typedArg.vecLen > 0) { // expected input is a vector, not a scalar + // typedArg.value = (context, props, batchId) => (fillArrayWithDefaults(userArgs[index](props), typedArg.vecLen)) + // } else { + typedArg.value = (context, props, batchId) => { + try { + return userArgs[index](props) + } catch (e) { + console.log('ERROR', e) + return input.default + } } - } else { - target[prop] = source[prop]; + // } + + typedArg.isUniform = true + } else if (userArgs[index].constructor === Array) { + // if (typedArg.vecLen > 0) { // expected input is a vector, not a scalar + // typedArg.isUniform = true + // typedArg.value = fillArrayWithDefaults(typedArg.value, typedArg.vecLen) + // } else { + // console.log("is Array") + typedArg.value = (context, props, batchId) => arrayUtils.getValue(userArgs[index])(props) + typedArg.isUniform = true + // } } } - } - return target; -} -function regexEscape(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); -} -var _entityMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/' -}; -function escape(data) { - if (typeof data === 'string') { - return data.replace(/[&<>"'\/]/g, function (s) { - return _entityMap[s]; - }); - } + if (startIndex < 0) { + } else { + if (typedArg.value && typedArg.value.transforms) { + const final_transform = typedArg.value.transforms[typedArg.value.transforms.length - 1] - return data; + if (final_transform.transform.glsl_return_type !== input.type) { + const defaults = DEFAULT_CONVERSIONS[input.type] + if (typeof defaults !== 'undefined') { + const default_def = defaults[final_transform.transform.glsl_return_type] + if (typeof default_def !== 'undefined') { + const { name, args } = default_def + typedArg.value = typedArg.value[name](...args) + } + } + } + + typedArg.isUniform = false + } else if (typedArg.type === 'float' && typeof typedArg.value === 'number') { + typedArg.value = ensure_decimal_dot(typedArg.value) + } else if (typedArg.type.startsWith('vec') && typeof typedArg.value === 'object' && Array.isArray(typedArg.value)) { + typedArg.isUniform = false + typedArg.value = `${typedArg.type}(${typedArg.value.map(ensure_decimal_dot).join(', ')})` + } else if (input.type === 'sampler2D') { + // typedArg.tex = typedArg.value + var x = typedArg.value + typedArg.value = () => (x.getTexture()) + typedArg.isUniform = true + } else { + // if passing in a texture reference, when function asks for vec4, convert to vec4 + if (typedArg.value.getTexture && input.type === 'vec4') { + var x1 = typedArg.value + typedArg.value = src(x1) + typedArg.isUniform = false + } + } + + // add tp uniform array if is a function that will pass in a different value on each render frame, + // or a texture/ external source + + if (typedArg.isUniform) { + typedArg.name += startIndex + // shaderParams.uniforms.push(typedArg) + } + } + return typedArg + }) } -var isIE10 = typeof window !== 'undefined' && window.navigator && window.navigator.userAgent && window.navigator.userAgent.indexOf('MSIE') > -1; -var chars = [' ', ',', '?', '!', ';']; -function looksLikeObjectPath(key, nsSeparator, keySeparator) { - nsSeparator = nsSeparator || ''; - keySeparator = keySeparator || ''; - var possibleChars = chars.filter(function (c) { - return nsSeparator.indexOf(c) < 0 && keySeparator.indexOf(c) < 0; - }); - if (possibleChars.length === 0) return true; - var r = new RegExp("(".concat(possibleChars.map(function (c) { - return c === '?' ? '\\?' : c; - }).join('|'), ")")); - var matched = !r.test(key); - if (!matched) { - var ki = key.indexOf(keySeparator); - if (ki > 0 && !r.test(key.substring(0, ki))) { - matched = true; - } - } +},{"./lib/array-utils.js":76}],70:[function(require,module,exports){ +const formatArguments = require('./format-arguments.js') - return matched; -} +// Add extra functionality to Array.prototype for generating sequences in time +const arrayUtils = require('./lib/array-utils.js') -function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } -function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } +// converts a tree of javascript functions to a shader +module.exports = function (transforms) { + var shaderParams = { + uniforms: [], // list of uniforms used in shader + glslFunctions: [], // list of functions used in shader + fragColor: '' + } -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } + var gen = generateGlsl(transforms, shaderParams)('st') + shaderParams.fragColor = gen + // remove uniforms with duplicate names + let uniforms = {} + shaderParams.uniforms.forEach((uniform) => uniforms[uniform.name] = uniform) + shaderParams.uniforms = Object.values(uniforms) + return shaderParams -function deepFind(obj, path) { - var keySeparator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '.'; - if (!obj) return undefined; - if (obj[path]) return obj[path]; - var paths = path.split(keySeparator); - var current = obj; +} - for (var i = 0; i < paths.length; ++i) { - if (!current) return undefined; - if (typeof current[paths[i]] === 'string' && i + 1 < paths.length) { - return undefined; - } +// recursive function for generating shader string from object containing functions and user arguments. Order of functions in string depends on type of function +// to do: improve variable names +function generateGlsl (transforms, shaderParams) { + // transform function that outputs a shader string corresponding to gl_FragColor + var fragColor = () => '' + // var uniforms = [] + // var glslFunctions = [] + transforms.forEach((transform) => { + var inputs = formatArguments(transform, shaderParams.uniforms.length) + inputs.forEach((input) => { + if(input.isUniform) shaderParams.uniforms.push(input) + }) - if (current[paths[i]] === undefined) { - var j = 2; - var p = paths.slice(i, i + j).join(keySeparator); - var mix = current[p]; + // add new glsl function to running list of functions + if(!contains(transform, shaderParams.glslFunctions)) shaderParams.glslFunctions.push(transform) - while (mix === undefined && paths.length > i + j) { - j++; - p = paths.slice(i, i + j).join(keySeparator); - mix = current[p]; - } + // current function for generating frag color shader code + var f0 = fragColor + if (transform.transform.type === 'src') { + fragColor = (uv) => `${shaderString(uv, transform.name, inputs, shaderParams)}` + } else if (transform.transform.type === 'coord') { + fragColor = (uv) => `${f0(`${shaderString(uv, transform.name, inputs, shaderParams)}`)}` + } else if (transform.transform.type === 'color') { + fragColor = (uv) => `${shaderString(`${f0(uv)}`, transform.name, inputs, shaderParams)}` + } else if (transform.transform.type === 'combine') { + // combining two generated shader strings (i.e. for blend, mult, add funtions) + var f1 = inputs[0].value && inputs[0].value.transforms ? + (uv) => `${generateGlsl(inputs[0].value.transforms, shaderParams)(uv)}` : + (inputs[0].isUniform ? () => inputs[0].name : () => inputs[0].value) + fragColor = (uv) => `${shaderString(`${f0(uv)}, ${f1(uv)}`, transform.name, inputs.slice(1), shaderParams)}` + } else if (transform.transform.type === 'combineCoord') { + // combining two generated shader strings (i.e. for modulate functions) + var f1 = inputs[0].value && inputs[0].value.transforms ? + (uv) => `${generateGlsl(inputs[0].value.transforms, shaderParams)(uv)}` : + (inputs[0].isUniform ? () => inputs[0].name : () => inputs[0].value) + fragColor = (uv) => `${f0(`${shaderString(`${uv}, ${f1(uv)}`, transform.name, inputs.slice(1), shaderParams)}`)}` - if (mix === undefined) return undefined; - if (path.endsWith(p)) { - if (typeof mix === 'string') return mix; - if (p && typeof mix[p] === 'string') return mix[p]; - } + } + }) +// console.log(fragColor) + // break; + return fragColor +} - var joinedPath = paths.slice(i + j).join(keySeparator); - if (joinedPath) return deepFind(mix, joinedPath, keySeparator); - return undefined; +// assembles a shader string containing the arguments and the function name, i.e. 'osc(uv, frequency)' +function shaderString (uv, method, inputs, shaderParams) { + const str = inputs.map((input) => { + if (input.isUniform) { + return input.name + } else if (input.value && input.value.transforms) { + // this by definition needs to be a generator, hence we start with 'st' as the initial value for generating the glsl fragment + return `${generateGlsl(input.value.transforms, shaderParams)('st')}` } + return input.value + }).reduce((p, c) => `${p}, ${c}`, '') - current = current[paths[i]]; - } + return `${method}(${uv}${str})` +} - return current; +// merge two arrays and remove duplicates +function mergeArrays (a, b) { + return a.concat(b.filter(function (item) { + return a.indexOf(item) < 0; + })) } -var ResourceStore = function (_EventEmitter) { - _inherits__default['default'](ResourceStore, _EventEmitter); +// check whether array +function contains(object, arr) { + for(var i = 0; i < arr.length; i++){ + if(object.name == arr[i].name) return true + } + return false +} - var _super = _createSuper(ResourceStore); - function ResourceStore(data) { - var _this; - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { - ns: ['translation'], - defaultNS: 'translation' - }; - _classCallCheck__default['default'](this, ResourceStore); +},{"./format-arguments.js":69,"./lib/array-utils.js":76}],71:[function(require,module,exports){ +const GlslSource = require('./glsl-source.js') - _this = _super.call(this); +class GeneratorFactory { + constructor ({ + defaultUniforms, + defaultOutput, + extendTransforms = [], + changeListener = (() => {}) + } = {} + ) { + this.defaultOutput = defaultOutput + this.defaultUniforms = defaultUniforms + this.changeListener = changeListener + this.extendTransforms = extendTransforms + this.generators = {} + this.init() + } + init () { + this.glslTransforms = {} + this.generators = Object.entries(this.generators).reduce((prev, [method, transform]) => { + this.changeListener({type: 'remove', synth: this, method}) + return prev + }, {}) - if (isIE10) { - EventEmitter.call(_assertThisInitialized__default['default'](_this)); - } + this.sourceClass = (() => { + return class extends GlslSource { + } + })() - _this.data = data || {}; - _this.options = options; + let functions = require('./glsl/glsl-functions.js')() - if (_this.options.keySeparator === undefined) { - _this.options.keySeparator = '.'; + // add user definied transforms + if (Array.isArray(this.extendTransforms)) { + functions.concat(this.extendTransforms) + } else if (typeof this.extendTransforms === 'object' && this.extendTransforms.type) { + functions.push(this.extendTransforms) } - if (_this.options.ignoreJSONStructure === undefined) { - _this.options.ignoreJSONStructure = true; + return functions.map((transform) => this.setFunction(transform)) + } + + _addMethod (method, transform) { + const self = this + this.glslTransforms[method] = transform + if (transform.type === 'src') { + const func = (...args) => new this.sourceClass({ + name: method, + transform: transform, + userArgs: args, + defaultOutput: this.defaultOutput, + defaultUniforms: this.defaultUniforms, + synth: self + }) + this.generators[method] = func + this.changeListener({type: 'add', synth: this, method}) + return func + } else { + this.sourceClass.prototype[method] = function (...args) { + this.transforms.push({name: method, transform: transform, userArgs: args, synth: self}) + return this + } } + return undefined + } - return _this; + setFunction(obj) { + var processedGlsl = processGlsl(obj) + if(processedGlsl) this._addMethod(obj.name, processedGlsl) } +} - _createClass__default['default'](ResourceStore, [{ - key: "addNamespaces", - value: function addNamespaces(ns) { - if (this.options.ns.indexOf(ns) < 0) { - this.options.ns.push(ns); - } - } - }, { - key: "removeNamespaces", - value: function removeNamespaces(ns) { - var index = this.options.ns.indexOf(ns); +const typeLookup = { + 'src': { + returnType: 'vec4', + args: ['vec2 _st'] + }, + 'coord': { + returnType: 'vec2', + args: ['vec2 _st'] + }, + 'color': { + returnType: 'vec4', + args: ['vec4 _c0'] + }, + 'combine': { + returnType: 'vec4', + args: ['vec4 _c0', 'vec4 _c1'] + }, + 'combineCoord': { + returnType: 'vec2', + args: ['vec2 _st', 'vec4 _c0'] + } +} +// expects glsl of format +// { +// name: 'osc', // name that will be used to access function as well as within glsl +// type: 'src', // can be src: vec4(vec2 _st), coord: vec2(vec2 _st), color: vec4(vec4 _c0), combine: vec4(vec4 _c0, vec4 _c1), combineCoord: vec2(vec2 _st, vec4 _c0) +// inputs: [ +// { +// name: 'freq', +// type: 'float', // 'float' //, 'texture', 'vec4' +// default: 0.2 +// }, +// { +// name: 'sync', +// type: 'float', +// default: 0.1 +// }, +// { +// name: 'offset', +// type: 'float', +// default: 0.0 +// } +// ], + // glsl: ` + // vec2 st = _st; + // float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; + // float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; + // float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; + // return vec4(r, g, b, 1.0); + // ` +// } - if (index > -1) { - this.options.ns.splice(index, 1); - } - } - }, { - key: "getResource", - value: function getResource(lng, ns, key) { - var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; - var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; - var ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure; - var path = [lng, ns]; - if (key && typeof key !== 'string') path = path.concat(key); - if (key && typeof key === 'string') path = path.concat(keySeparator ? key.split(keySeparator) : key); +// // generates glsl function: +// `vec4 osc(vec2 _st, float freq, float sync, float offset){ +// vec2 st = _st; +// float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; +// float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; +// float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; +// return vec4(r, g, b, 1.0); +// }` - if (lng.indexOf('.') > -1) { - path = lng.split('.'); - } +function processGlsl(obj) { + let t = typeLookup[obj.type] + if(t) { + let baseArgs = t.args.map((arg) => arg).join(", ") + // @todo: make sure this works for all input types, add validation + let customArgs = obj.inputs.map((input) => `${input.type} ${input.name}`).join(', ') + let args = `${baseArgs}${customArgs.length > 0 ? ', '+ customArgs: ''}` +// console.log('args are ', args) - var result = getPath(this.data, path); - if (result || !ignoreJSONStructure || typeof key !== 'string') return result; - return deepFind(this.data && this.data[lng] && this.data[lng][ns], key, keySeparator); - } - }, { - key: "addResource", - value: function addResource(lng, ns, key, value) { - var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : { - silent: false - }; - var keySeparator = this.options.keySeparator; - if (keySeparator === undefined) keySeparator = '.'; - var path = [lng, ns]; - if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key); + let glslFunction = +` + ${t.returnType} ${obj.name}(${args}) { + ${obj.glsl} + } +` - if (lng.indexOf('.') > -1) { - path = lng.split('.'); - value = ns; - ns = path[1]; - } + // add extra input to beginning for backward combatibility @todo update compiler so this is no longer necessary + if(obj.type === 'combine' || obj.type === 'combineCoord') obj.inputs.unshift({ + name: 'color', + type: 'vec4' + }) + return Object.assign({}, obj, { glsl: glslFunction}) + } else { + console.warn(`type ${obj.type} not recognized`, obj) + } - this.addNamespaces(ns); - setPath(this.data, path, value); - if (!options.silent) this.emit('added', lng, ns, key, value); - } - }, { - key: "addResources", - value: function addResources(lng, ns, resources) { - var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : { - silent: false - }; +} - for (var m in resources) { - if (typeof resources[m] === 'string' || Object.prototype.toString.apply(resources[m]) === '[object Array]') this.addResource(lng, ns, m, resources[m], { - silent: true - }); - } +module.exports = GeneratorFactory - if (!options.silent) this.emit('added', lng, ns, resources); - } - }, { - key: "addResourceBundle", - value: function addResourceBundle(lng, ns, resources, deep, overwrite) { - var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : { - silent: false - }; - var path = [lng, ns]; +},{"./glsl-source.js":72,"./glsl/glsl-functions.js":73}],72:[function(require,module,exports){ +const generateGlsl = require('./generate-glsl.js') +// const formatArguments = require('./glsl-utils.js').formatArguments - if (lng.indexOf('.') > -1) { - path = lng.split('.'); - deep = resources; - resources = ns; - ns = path[1]; - } +// const glslTransforms = require('./glsl/composable-glsl-functions.js') +const utilityGlsl = require('./glsl/utility-functions.js') - this.addNamespaces(ns); - var pack = getPath(this.data, path) || {}; +var GlslSource = function (obj) { + this.transforms = [] + this.transforms.push(obj) + this.defaultOutput = obj.defaultOutput + this.synth = obj.synth + this.type = 'GlslSource' + this.defaultUniforms = obj.defaultUniforms + return this +} - if (deep) { - deepExtend(pack, resources, overwrite); - } else { - pack = _objectSpread$1(_objectSpread$1({}, pack), resources); - } +GlslSource.prototype.addTransform = function (obj) { + this.transforms.push(obj) +} - setPath(this.data, path, pack); - if (!options.silent) this.emit('added', lng, ns, resources); - } - }, { - key: "removeResourceBundle", - value: function removeResourceBundle(lng, ns) { - if (this.hasResourceBundle(lng, ns)) { - delete this.data[lng][ns]; - } +GlslSource.prototype.out = function (_output) { + var output = _output || this.defaultOutput + var glsl = this.glsl(output) + this.synth.currentFunctions = [] + // output.renderPasses(glsl) + if(output) try{ + output.render(glsl) + } catch (error) { + console.log('shader could not compile', error) + } +} - this.removeNamespaces(ns); - this.emit('removed', lng, ns); - } - }, { - key: "hasResourceBundle", - value: function hasResourceBundle(lng, ns) { - return this.getResource(lng, ns) !== undefined; - } - }, { - key: "getResourceBundle", - value: function getResourceBundle(lng, ns) { - if (!ns) ns = this.options.defaultNS; - if (this.options.compatibilityAPI === 'v1') return _objectSpread$1(_objectSpread$1({}, {}), this.getResource(lng, ns)); - return this.getResource(lng, ns); - } - }, { - key: "getDataByLanguage", - value: function getDataByLanguage(lng) { - return this.data[lng]; - } - }, { - key: "hasLanguageSomeTranslations", - value: function hasLanguageSomeTranslations(lng) { - var data = this.getDataByLanguage(lng); - var n = data && Object.keys(data) || []; - return !!n.find(function (v) { - return data[v] && Object.keys(data[v]).length > 0; - }); +GlslSource.prototype.glsl = function () { + //var output = _output || this.defaultOutput + var self = this + // uniforms included in all shaders +// this.defaultUniforms = output.uniforms + var passes = [] + var transforms = [] +// console.log('output', output) + this.transforms.forEach((transform) => { + if(transform.transform.type === 'renderpass'){ + // if (transforms.length > 0) passes.push(this.compile(transforms, output)) + // transforms = [] + // var uniforms = {} + // const inputs = formatArguments(transform, -1) + // inputs.forEach((uniform) => { uniforms[uniform.name] = uniform.value }) + // + // passes.push({ + // frag: transform.transform.frag, + // uniforms: Object.assign({}, self.defaultUniforms, uniforms) + // }) + // transforms.push({name: 'prev', transform: glslTransforms['prev'], synth: this.synth}) + console.warn('no support for renderpass') + } else { + transforms.push(transform) } - }, { - key: "toJSON", - value: function toJSON() { - return this.data; + }) + + if (transforms.length > 0) passes.push(this.compile(transforms)) + + return passes +} + +GlslSource.prototype.compile = function (transforms) { + var shaderInfo = generateGlsl(transforms, this.synth) + var uniforms = {} + shaderInfo.uniforms.forEach((uniform) => { uniforms[uniform.name] = uniform.value }) + + var frag = ` + precision ${this.defaultOutput.precision} float; + ${Object.values(shaderInfo.uniforms).map((uniform) => { + let type = uniform.type + switch (uniform.type) { + case 'texture': + type = 'sampler2D' + break } - }]); + return ` + uniform ${type} ${uniform.name};` + }).join('')} + uniform float time; + uniform vec2 resolution; + varying vec2 uv; + uniform sampler2D prevBuffer; - return ResourceStore; -}(EventEmitter); + ${Object.values(utilityGlsl).map((transform) => { + // console.log(transform.glsl) + return ` + ${transform.glsl} + ` + }).join('')} -var postProcessor = { - processors: {}, - addPostProcessor: function addPostProcessor(module) { - this.processors[module.name] = module; - }, - handle: function handle(processors, value, key, options, translator) { - var _this = this; + ${shaderInfo.glslFunctions.map((transform) => { + return ` + ${transform.transform.glsl} + ` + }).join('')} - processors.forEach(function (processor) { - if (_this.processors[processor]) value = _this.processors[processor].process(value, key, options, translator); - }); - return value; + void main () { + vec4 c = vec4(1, 0, 0, 1); + vec2 st = gl_FragCoord.xy/resolution.xy; + gl_FragColor = ${shaderInfo.fragColor}; } -}; + ` -function ownKeys$2(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } + return { + frag: frag, + uniforms: Object.assign({}, this.defaultUniforms, uniforms) + } -function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$2(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$2(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } +} -function _createSuper$1(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } +module.exports = GlslSource -function _isNativeReflectConstruct$1() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } -var checkedLoadedFor = {}; +},{"./generate-glsl.js":70,"./glsl/utility-functions.js":74}],73:[function(require,module,exports){ +/* +Format for adding functions to hydra. For each entry in this file, hydra automatically generates a glsl function and javascript function with the same name. You can also ass functions dynamically using setFunction(object). -var Translator = function (_EventEmitter) { - _inherits__default['default'](Translator, _EventEmitter); +{ + name: 'osc', // name that will be used to access function in js as well as in glsl + type: 'src', // can be 'src', 'color', 'combine', 'combineCoords'. see below for more info + inputs: [ + { + name: 'freq', + type: 'float', + default: 0.2 + }, + { + name: 'sync', + type: 'float', + default: 0.1 + }, + { + name: 'offset', + type: 'float', + default: 0.0 + } + ], + glsl: ` + vec2 st = _st; + float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; + float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; + float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; + return vec4(r, g, b, 1.0); + ` +} - var _super = _createSuper$1(Translator); +// The above code generates the glsl function: +`vec4 osc(vec2 _st, float freq, float sync, float offset){ + vec2 st = _st; + float r = sin((st.x-offset*2/freq+time*sync)*freq)*0.5 + 0.5; + float g = sin((st.x+time*sync)*freq)*0.5 + 0.5; + float b = sin((st.x+offset/freq+time*sync)*freq)*0.5 + 0.5; + return vec4(r, g, b, 1.0); +}` - function Translator(services) { - var _this; - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; +Types and default arguments for hydra functions. +The value in the 'type' field lets the parser know which type the function will be returned as well as default arguments. - _classCallCheck__default['default'](this, Translator); +const types = { + 'src': { + returnType: 'vec4', + args: ['vec2 _st'] + }, + 'coord': { + returnType: 'vec2', + args: ['vec2 _st'] + }, + 'color': { + returnType: 'vec4', + args: ['vec4 _c0'] + }, + 'combine': { + returnType: 'vec4', + args: ['vec4 _c0', 'vec4 _c1'] + }, + 'combineCoord': { + returnType: 'vec2', + args: ['vec2 _st', 'vec4 _c0'] + } +} - _this = _super.call(this); +*/ - if (isIE10) { - EventEmitter.call(_assertThisInitialized__default['default'](_this)); +module.exports = () => [ + { + name: 'noise', + type: 'src', + inputs: [ + { + type: 'float', + name: 'scale', + default: 10, + }, +{ + type: 'float', + name: 'offset', + default: 0.1, } - - copy(['resourceStore', 'languageUtils', 'pluralResolver', 'interpolator', 'backendConnector', 'i18nFormat', 'utils'], services, _assertThisInitialized__default['default'](_this)); - _this.options = options; - - if (_this.options.keySeparator === undefined) { - _this.options.keySeparator = '.'; + ], + glsl: +` return vec4(vec3(_noise(vec3(_st*scale, offset*time))), 1.0);` +}, +{ + name: 'voronoi', + type: 'src', + inputs: [ + { + type: 'float', + name: 'scale', + default: 5, + }, +{ + type: 'float', + name: 'speed', + default: 0.3, + }, +{ + type: 'float', + name: 'blending', + default: 0.3, } - - _this.logger = baseLogger.create('translator'); - return _this; - } - - _createClass__default['default'](Translator, [{ - key: "changeLanguage", - value: function changeLanguage(lng) { - if (lng) this.language = lng; + ], + glsl: +` vec3 color = vec3(.0); + // Scale + _st *= scale; + // Tile the space + vec2 i_st = floor(_st); + vec2 f_st = fract(_st); + float m_dist = 10.; // minimun distance + vec2 m_point; // minimum point + for (int j=-1; j<=1; j++ ) { + for (int i=-1; i<=1; i++ ) { + vec2 neighbor = vec2(float(i),float(j)); + vec2 p = i_st + neighbor; + vec2 point = fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453); + point = 0.5 + 0.5*sin(time*speed + 6.2831*point); + vec2 diff = neighbor + point - f_st; + float dist = length(diff); + if( dist < m_dist ) { + m_dist = dist; + m_point = point; + } + } + } + // Assign a color using the closest point position + color += dot(m_point,vec2(.3,.6)); + color *= 1.0 - blending*m_dist; + return vec4(color, 1.0);` +}, +{ + name: 'osc', + type: 'src', + inputs: [ + { + type: 'float', + name: 'frequency', + default: 60, + }, +{ + type: 'float', + name: 'sync', + default: 0.1, + }, +{ + type: 'float', + name: 'offset', + default: 0, } - }, { - key: "exists", - value: function exists(key) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { - interpolation: {} - }; - - if (key === undefined || key === null) { - return false; - } - - var resolved = this.resolve(key, options); - return resolved && resolved.res !== undefined; + ], + glsl: +` vec2 st = _st; + float r = sin((st.x-offset/frequency+time*sync)*frequency)*0.5 + 0.5; + float g = sin((st.x+time*sync)*frequency)*0.5 + 0.5; + float b = sin((st.x+offset/frequency+time*sync)*frequency)*0.5 + 0.5; + return vec4(r, g, b, 1.0);` +}, +{ + name: 'shape', + type: 'src', + inputs: [ + { + type: 'float', + name: 'sides', + default: 3, + }, +{ + type: 'float', + name: 'radius', + default: 0.3, + }, +{ + type: 'float', + name: 'smoothing', + default: 0.01, } - }, { - key: "extractFromKey", - value: function extractFromKey(key, options) { - var nsSeparator = options.nsSeparator !== undefined ? options.nsSeparator : this.options.nsSeparator; - if (nsSeparator === undefined) nsSeparator = ':'; - var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; - var namespaces = options.ns || this.options.defaultNS || []; - var wouldCheckForNsInKey = nsSeparator && key.indexOf(nsSeparator) > -1; - var seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !options.keySeparator && !this.options.userDefinedNsSeparator && !options.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator); - - if (wouldCheckForNsInKey && !seemsNaturalLanguage) { - var m = key.match(this.interpolator.nestingRegexp); - - if (m && m.length > 0) { - return { - key: key, - namespaces: namespaces - }; - } - - var parts = key.split(nsSeparator); - if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.indexOf(parts[0]) > -1) namespaces = parts.shift(); - key = parts.join(keySeparator); - } - - if (typeof namespaces === 'string') namespaces = [namespaces]; - return { - key: key, - namespaces: namespaces - }; + ], + glsl: +` vec2 st = _st * 2. - 1.; + // Angle and radius from the current pixel + float a = atan(st.x,st.y)+3.1416; + float r = (2.*3.1416)/sides; + float d = cos(floor(.5+a/r)*r-a)*length(st); + return vec4(vec3(1.0-smoothstep(radius,radius + smoothing + 0.0000001,d)), 1.0);` +}, +{ + name: 'gradient', + type: 'src', + inputs: [ + { + type: 'float', + name: 'speed', + default: 0, + } + ], + glsl: +` return vec4(_st, sin(time*speed), 1.0);` +}, +{ + name: 'src', + type: 'src', + inputs: [ + { + type: 'sampler2D', + name: 'tex', + default: NaN, + } + ], + glsl: +` // vec2 uv = gl_FragCoord.xy/vec2(1280., 720.); + return texture2D(tex, fract(_st));` +}, +{ + name: 'solid', + type: 'src', + inputs: [ + { + type: 'float', + name: 'r', + default: 0, + }, +{ + type: 'float', + name: 'g', + default: 0, + }, +{ + type: 'float', + name: 'b', + default: 0, + }, +{ + type: 'float', + name: 'a', + default: 1, + } + ], + glsl: +` return vec4(r, g, b, a);` +}, +{ + name: 'rotate', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'angle', + default: 10, + }, +{ + type: 'float', + name: 'speed', + default: 0, + } + ], + glsl: +` vec2 xy = _st - vec2(0.5); + float ang = angle + speed *time; + xy = mat2(cos(ang),-sin(ang), sin(ang),cos(ang))*xy; + xy += 0.5; + return xy;` +}, +{ + name: 'scale', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'amount', + default: 1.5, + }, +{ + type: 'float', + name: 'xMult', + default: 1, + }, +{ + type: 'float', + name: 'yMult', + default: 1, + }, +{ + type: 'float', + name: 'offsetX', + default: 0.5, + }, +{ + type: 'float', + name: 'offsetY', + default: 0.5, + } + ], + glsl: +` vec2 xy = _st - vec2(offsetX, offsetY); + xy*=(1.0/vec2(amount*xMult, amount*yMult)); + xy+=vec2(offsetX, offsetY); + return xy; + ` +}, +{ + name: 'pixelate', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'pixelX', + default: 20, + }, +{ + type: 'float', + name: 'pixelY', + default: 20, + } + ], + glsl: +` vec2 xy = vec2(pixelX, pixelY); + return (floor(_st * xy) + 0.5)/xy;` +}, +{ + name: 'posterize', + type: 'color', + inputs: [ + { + type: 'float', + name: 'bins', + default: 3, + }, +{ + type: 'float', + name: 'gamma', + default: 0.6, + } + ], + glsl: +` vec4 c2 = pow(_c0, vec4(gamma)); + c2 *= vec4(bins); + c2 = floor(c2); + c2/= vec4(bins); + c2 = pow(c2, vec4(1.0/gamma)); + return vec4(c2.xyz, _c0.a);` +}, +{ + name: 'shift', + type: 'color', + inputs: [ + { + type: 'float', + name: 'r', + default: 0.5, + }, +{ + type: 'float', + name: 'g', + default: 0, + }, +{ + type: 'float', + name: 'b', + default: 0, + }, +{ + type: 'float', + name: 'a', + default: 0, + } + ], + glsl: +` vec4 c2 = vec4(_c0); + c2.r = fract(c2.r + r); + c2.g = fract(c2.g + g); + c2.b = fract(c2.b + b); + c2.a = fract(c2.a + a); + return vec4(c2.rgba);` +}, +{ + name: 'repeat', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'repeatX', + default: 3, + }, +{ + type: 'float', + name: 'repeatY', + default: 3, + }, +{ + type: 'float', + name: 'offsetX', + default: 0, + }, +{ + type: 'float', + name: 'offsetY', + default: 0, + } + ], + glsl: +` vec2 st = _st * vec2(repeatX, repeatY); + st.x += step(1., mod(st.y,2.0)) * offsetX; + st.y += step(1., mod(st.x,2.0)) * offsetY; + return fract(st);` +}, +{ + name: 'modulateRepeat', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'repeatX', + default: 3, + }, +{ + type: 'float', + name: 'repeatY', + default: 3, + }, +{ + type: 'float', + name: 'offsetX', + default: 0.5, + }, +{ + type: 'float', + name: 'offsetY', + default: 0.5, } - }, { - key: "translate", - value: function translate(keys, options, lastKey) { - var _this2 = this; - - if (_typeof__default['default'](options) !== 'object' && this.options.overloadTranslationOptionHandler) { - options = this.options.overloadTranslationOptionHandler(arguments); - } - - if (!options) options = {}; - if (keys === undefined || keys === null) return ''; - if (!Array.isArray(keys)) keys = [String(keys)]; - var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; - - var _this$extractFromKey = this.extractFromKey(keys[keys.length - 1], options), - key = _this$extractFromKey.key, - namespaces = _this$extractFromKey.namespaces; - - var namespace = namespaces[namespaces.length - 1]; - var lng = options.lng || this.language; - var appendNamespaceToCIMode = options.appendNamespaceToCIMode || this.options.appendNamespaceToCIMode; - - if (lng && lng.toLowerCase() === 'cimode') { - if (appendNamespaceToCIMode) { - var nsSeparator = options.nsSeparator || this.options.nsSeparator; - return namespace + nsSeparator + key; - } - - return key; - } - - var resolved = this.resolve(keys, options); - var res = resolved && resolved.res; - var resUsedKey = resolved && resolved.usedKey || key; - var resExactUsedKey = resolved && resolved.exactUsedKey || key; - var resType = Object.prototype.toString.apply(res); - var noObject = ['[object Number]', '[object Function]', '[object RegExp]']; - var joinArrays = options.joinArrays !== undefined ? options.joinArrays : this.options.joinArrays; - var handleAsObjectInI18nFormat = !this.i18nFormat || this.i18nFormat.handleAsObject; - var handleAsObject = typeof res !== 'string' && typeof res !== 'boolean' && typeof res !== 'number'; - - if (handleAsObjectInI18nFormat && res && handleAsObject && noObject.indexOf(resType) < 0 && !(typeof joinArrays === 'string' && resType === '[object Array]')) { - if (!options.returnObjects && !this.options.returnObjects) { - if (!this.options.returnedObjectHandler) { - this.logger.warn('accessing an object - but returnObjects options is not enabled!'); - } - - return this.options.returnedObjectHandler ? this.options.returnedObjectHandler(resUsedKey, res, _objectSpread$2(_objectSpread$2({}, options), {}, { - ns: namespaces - })) : "key '".concat(key, " (").concat(this.language, ")' returned an object instead of string."); - } - - if (keySeparator) { - var resTypeIsArray = resType === '[object Array]'; - var copy = resTypeIsArray ? [] : {}; - var newKeyToUse = resTypeIsArray ? resExactUsedKey : resUsedKey; - - for (var m in res) { - if (Object.prototype.hasOwnProperty.call(res, m)) { - var deepKey = "".concat(newKeyToUse).concat(keySeparator).concat(m); - copy[m] = this.translate(deepKey, _objectSpread$2(_objectSpread$2({}, options), { - joinArrays: false, - ns: namespaces - })); - if (copy[m] === deepKey) copy[m] = res[m]; - } - } - - res = copy; - } - } else if (handleAsObjectInI18nFormat && typeof joinArrays === 'string' && resType === '[object Array]') { - res = res.join(joinArrays); - if (res) res = this.extendTranslation(res, keys, options, lastKey); - } else { - var usedDefault = false; - var usedKey = false; - var needsPluralHandling = options.count !== undefined && typeof options.count !== 'string'; - var hasDefaultValue = Translator.hasDefaultValue(options); - var defaultValueSuffix = needsPluralHandling ? this.pluralResolver.getSuffix(lng, options.count, options) : ''; - var defaultValue = options["defaultValue".concat(defaultValueSuffix)] || options.defaultValue; - - if (!this.isValidLookup(res) && hasDefaultValue) { - usedDefault = true; - res = defaultValue; - } - - if (!this.isValidLookup(res)) { - usedKey = true; - res = key; - } - - var missingKeyNoValueFallbackToKey = options.missingKeyNoValueFallbackToKey || this.options.missingKeyNoValueFallbackToKey; - var resForMissing = missingKeyNoValueFallbackToKey && usedKey ? undefined : res; - var updateMissing = hasDefaultValue && defaultValue !== res && this.options.updateMissing; - - if (usedKey || usedDefault || updateMissing) { - this.logger.log(updateMissing ? 'updateKey' : 'missingKey', lng, namespace, key, updateMissing ? defaultValue : res); - - if (keySeparator) { - var fk = this.resolve(key, _objectSpread$2(_objectSpread$2({}, options), {}, { - keySeparator: false - })); - if (fk && fk.res) this.logger.warn('Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.'); - } - - var lngs = []; - var fallbackLngs = this.languageUtils.getFallbackCodes(this.options.fallbackLng, options.lng || this.language); - - if (this.options.saveMissingTo === 'fallback' && fallbackLngs && fallbackLngs[0]) { - for (var i = 0; i < fallbackLngs.length; i++) { - lngs.push(fallbackLngs[i]); - } - } else if (this.options.saveMissingTo === 'all') { - lngs = this.languageUtils.toResolveHierarchy(options.lng || this.language); - } else { - lngs.push(options.lng || this.language); - } - - var send = function send(l, k, specificDefaultValue) { - var defaultForMissing = hasDefaultValue && specificDefaultValue !== res ? specificDefaultValue : resForMissing; - - if (_this2.options.missingKeyHandler) { - _this2.options.missingKeyHandler(l, namespace, k, defaultForMissing, updateMissing, options); - } else if (_this2.backendConnector && _this2.backendConnector.saveMissing) { - _this2.backendConnector.saveMissing(l, namespace, k, defaultForMissing, updateMissing, options); - } - - _this2.emit('missingKey', l, namespace, k, res); - }; - - if (this.options.saveMissing) { - if (this.options.saveMissingPlurals && needsPluralHandling) { - lngs.forEach(function (language) { - _this2.pluralResolver.getSuffixes(language).forEach(function (suffix) { - send([language], key + suffix, options["defaultValue".concat(suffix)] || defaultValue); - }); - }); - } else { - send(lngs, key, defaultValue); - } - } - } - - res = this.extendTranslation(res, keys, options, resolved, lastKey); - if (usedKey && res === key && this.options.appendNamespaceToMissingKey) res = "".concat(namespace, ":").concat(key); - - if ((usedKey || usedDefault) && this.options.parseMissingKeyHandler) { - if (this.options.compatibilityAPI !== 'v1') { - res = this.options.parseMissingKeyHandler(key, usedDefault ? res : undefined); - } else { - res = this.options.parseMissingKeyHandler(res); - } - } - } - - return res; + ], + glsl: +` vec2 st = _st * vec2(repeatX, repeatY); + st.x += step(1., mod(st.y,2.0)) + _c0.r * offsetX; + st.y += step(1., mod(st.x,2.0)) + _c0.g * offsetY; + return fract(st);` +}, +{ + name: 'repeatX', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'reps', + default: 3, + }, +{ + type: 'float', + name: 'offset', + default: 0, } - }, { - key: "extendTranslation", - value: function extendTranslation(res, key, options, resolved, lastKey) { - var _this3 = this; - - if (this.i18nFormat && this.i18nFormat.parse) { - res = this.i18nFormat.parse(res, options, resolved.usedLng, resolved.usedNS, resolved.usedKey, { - resolved: resolved - }); - } else if (!options.skipInterpolation) { - if (options.interpolation) this.interpolator.init(_objectSpread$2(_objectSpread$2({}, options), { - interpolation: _objectSpread$2(_objectSpread$2({}, this.options.interpolation), options.interpolation) - })); - var skipOnVariables = typeof res === 'string' && (options && options.interpolation && options.interpolation.skipOnVariables !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables); - var nestBef; - - if (skipOnVariables) { - var nb = res.match(this.interpolator.nestingRegexp); - nestBef = nb && nb.length; - } - - var data = options.replace && typeof options.replace !== 'string' ? options.replace : options; - if (this.options.interpolation.defaultVariables) data = _objectSpread$2(_objectSpread$2({}, this.options.interpolation.defaultVariables), data); - res = this.interpolator.interpolate(res, data, options.lng || this.language, options); - - if (skipOnVariables) { - var na = res.match(this.interpolator.nestingRegexp); - var nestAft = na && na.length; - if (nestBef < nestAft) options.nest = false; - } - - if (options.nest !== false) res = this.interpolator.nest(res, function () { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - if (lastKey && lastKey[0] === args[0] && !options.context) { - _this3.logger.warn("It seems you are nesting recursively key: ".concat(args[0], " in key: ").concat(key[0])); - - return null; - } - - return _this3.translate.apply(_this3, args.concat([key])); - }, options); - if (options.interpolation) this.interpolator.reset(); - } - - var postProcess = options.postProcess || this.options.postProcess; - var postProcessorNames = typeof postProcess === 'string' ? [postProcess] : postProcess; - - if (res !== undefined && res !== null && postProcessorNames && postProcessorNames.length && options.applyPostProcessor !== false) { - res = postProcessor.handle(postProcessorNames, res, key, this.options && this.options.postProcessPassResolved ? _objectSpread$2({ - i18nResolved: resolved - }, options) : options, this); - } - - return res; + ], + glsl: +` vec2 st = _st * vec2(reps, 1.0); + // float f = mod(_st.y,2.0); + st.y += step(1., mod(st.x,2.0))* offset; + return fract(st);` +}, +{ + name: 'modulateRepeatX', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'reps', + default: 3, + }, +{ + type: 'float', + name: 'offset', + default: 0.5, } - }, { - key: "resolve", - value: function resolve(keys) { - var _this4 = this; - - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var found; - var usedKey; - var exactUsedKey; - var usedLng; - var usedNS; - if (typeof keys === 'string') keys = [keys]; - keys.forEach(function (k) { - if (_this4.isValidLookup(found)) return; - - var extracted = _this4.extractFromKey(k, options); - - var key = extracted.key; - usedKey = key; - var namespaces = extracted.namespaces; - if (_this4.options.fallbackNS) namespaces = namespaces.concat(_this4.options.fallbackNS); - var needsPluralHandling = options.count !== undefined && typeof options.count !== 'string'; - - var needsZeroSuffixLookup = needsPluralHandling && !options.ordinal && options.count === 0 && _this4.pluralResolver.shouldUseIntlApi(); - - var needsContextHandling = options.context !== undefined && (typeof options.context === 'string' || typeof options.context === 'number') && options.context !== ''; - var codes = options.lngs ? options.lngs : _this4.languageUtils.toResolveHierarchy(options.lng || _this4.language, options.fallbackLng); - namespaces.forEach(function (ns) { - if (_this4.isValidLookup(found)) return; - usedNS = ns; - - if (!checkedLoadedFor["".concat(codes[0], "-").concat(ns)] && _this4.utils && _this4.utils.hasLoadedNamespace && !_this4.utils.hasLoadedNamespace(usedNS)) { - checkedLoadedFor["".concat(codes[0], "-").concat(ns)] = true; - - _this4.logger.warn("key \"".concat(usedKey, "\" for languages \"").concat(codes.join(', '), "\" won't get resolved as namespace \"").concat(usedNS, "\" was not yet loaded"), 'This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!'); - } - - codes.forEach(function (code) { - if (_this4.isValidLookup(found)) return; - usedLng = code; - var finalKeys = [key]; - - if (_this4.i18nFormat && _this4.i18nFormat.addLookupKeys) { - _this4.i18nFormat.addLookupKeys(finalKeys, key, code, ns, options); - } else { - var pluralSuffix; - if (needsPluralHandling) pluralSuffix = _this4.pluralResolver.getSuffix(code, options.count, options); - var zeroSuffix = '_zero'; - - if (needsPluralHandling) { - finalKeys.push(key + pluralSuffix); - - if (needsZeroSuffixLookup) { - finalKeys.push(key + zeroSuffix); - } - } - - if (needsContextHandling) { - var contextKey = "".concat(key).concat(_this4.options.contextSeparator).concat(options.context); - finalKeys.push(contextKey); - - if (needsPluralHandling) { - finalKeys.push(contextKey + pluralSuffix); - - if (needsZeroSuffixLookup) { - finalKeys.push(contextKey + zeroSuffix); - } - } - } - } - - var possibleKey; - - while (possibleKey = finalKeys.pop()) { - if (!_this4.isValidLookup(found)) { - exactUsedKey = possibleKey; - found = _this4.getResource(code, ns, possibleKey, options); - } - } - }); - }); - }); - return { - res: found, - usedKey: usedKey, - exactUsedKey: exactUsedKey, - usedLng: usedLng, - usedNS: usedNS - }; + ], + glsl: +` vec2 st = _st * vec2(reps, 1.0); + // float f = mod(_st.y,2.0); + st.y += step(1., mod(st.x,2.0)) + _c0.r * offset; + return fract(st);` +}, +{ + name: 'repeatY', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'reps', + default: 3, + }, +{ + type: 'float', + name: 'offset', + default: 0, } - }, { - key: "isValidLookup", - value: function isValidLookup(res) { - return res !== undefined && !(!this.options.returnNull && res === null) && !(!this.options.returnEmptyString && res === ''); + ], + glsl: +` vec2 st = _st * vec2(1.0, reps); + // float f = mod(_st.y,2.0); + st.x += step(1., mod(st.y,2.0))* offset; + return fract(st);` +}, +{ + name: 'modulateRepeatY', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'reps', + default: 3, + }, +{ + type: 'float', + name: 'offset', + default: 0.5, } - }, { - key: "getResource", - value: function getResource(code, ns, key) { - var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; - if (this.i18nFormat && this.i18nFormat.getResource) return this.i18nFormat.getResource(code, ns, key, options); - return this.resourceStore.getResource(code, ns, key, options); + ], + glsl: +` vec2 st = _st * vec2(reps, 1.0); + // float f = mod(_st.y,2.0); + st.x += step(1., mod(st.y,2.0)) + _c0.r * offset; + return fract(st);` +}, +{ + name: 'kaleid', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'nSides', + default: 4, } - }], [{ - key: "hasDefaultValue", - value: function hasDefaultValue(options) { - var prefix = 'defaultValue'; - - for (var option in options) { - if (Object.prototype.hasOwnProperty.call(options, option) && prefix === option.substring(0, prefix.length) && undefined !== options[option]) { - return true; - } - } - - return false; + ], + glsl: +` vec2 st = _st; + st -= 0.5; + float r = length(st); + float a = atan(st.y, st.x); + float pi = 2.*3.1416; + a = mod(a,pi/nSides); + a = abs(a-pi/nSides/2.); + return r*vec2(cos(a), sin(a));` +}, +{ + name: 'modulateKaleid', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'nSides', + default: 4, } - }]); - - return Translator; -}(EventEmitter); - -function capitalize(string) { - return string.charAt(0).toUpperCase() + string.slice(1); -} - -var LanguageUtil = function () { - function LanguageUtil(options) { - _classCallCheck__default['default'](this, LanguageUtil); - - this.options = options; - this.supportedLngs = this.options.supportedLngs || false; - this.logger = baseLogger.create('languageUtils'); - } - - _createClass__default['default'](LanguageUtil, [{ - key: "getScriptPartFromCode", - value: function getScriptPartFromCode(code) { - if (!code || code.indexOf('-') < 0) return null; - var p = code.split('-'); - if (p.length === 2) return null; - p.pop(); - if (p[p.length - 1].toLowerCase() === 'x') return null; - return this.formatLanguageCode(p.join('-')); + ], + glsl: +` vec2 st = _st - 0.5; + float r = length(st); + float a = atan(st.y, st.x); + float pi = 2.*3.1416; + a = mod(a,pi/nSides); + a = abs(a-pi/nSides/2.); + return (_c0.r+r)*vec2(cos(a), sin(a));` +}, +{ + name: 'scroll', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'scrollX', + default: 0.5, + }, +{ + type: 'float', + name: 'scrollY', + default: 0.5, + }, +{ + type: 'float', + name: 'speedX', + default: 0, + }, +{ + type: 'float', + name: 'speedY', + default: 0, + } + ], + glsl: +` + _st.x += scrollX + time*speedX; + _st.y += scrollY + time*speedY; + return fract(_st);` +}, +{ + name: 'scrollX', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'scrollX', + default: 0.5, + }, +{ + type: 'float', + name: 'speed', + default: 0, } - }, { - key: "getLanguagePartFromCode", - value: function getLanguagePartFromCode(code) { - if (!code || code.indexOf('-') < 0) return code; - var p = code.split('-'); - return this.formatLanguageCode(p[0]); + ], + glsl: +` _st.x += scrollX + time*speed; + return fract(_st);` +}, +{ + name: 'modulateScrollX', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'scrollX', + default: 0.5, + }, +{ + type: 'float', + name: 'speed', + default: 0, } - }, { - key: "formatLanguageCode", - value: function formatLanguageCode(code) { - if (typeof code === 'string' && code.indexOf('-') > -1) { - var specialCases = ['hans', 'hant', 'latn', 'cyrl', 'cans', 'mong', 'arab']; - var p = code.split('-'); - - if (this.options.lowerCaseLng) { - p = p.map(function (part) { - return part.toLowerCase(); - }); - } else if (p.length === 2) { - p[0] = p[0].toLowerCase(); - p[1] = p[1].toUpperCase(); - if (specialCases.indexOf(p[1].toLowerCase()) > -1) p[1] = capitalize(p[1].toLowerCase()); - } else if (p.length === 3) { - p[0] = p[0].toLowerCase(); - if (p[1].length === 2) p[1] = p[1].toUpperCase(); - if (p[0] !== 'sgn' && p[2].length === 2) p[2] = p[2].toUpperCase(); - if (specialCases.indexOf(p[1].toLowerCase()) > -1) p[1] = capitalize(p[1].toLowerCase()); - if (specialCases.indexOf(p[2].toLowerCase()) > -1) p[2] = capitalize(p[2].toLowerCase()); - } - - return p.join('-'); - } - - return this.options.cleanCode || this.options.lowerCaseLng ? code.toLowerCase() : code; + ], + glsl: +` _st.x += _c0.r*scrollX + time*speed; + return fract(_st);` +}, +{ + name: 'scrollY', + type: 'coord', + inputs: [ + { + type: 'float', + name: 'scrollY', + default: 0.5, + }, +{ + type: 'float', + name: 'speed', + default: 0, } - }, { - key: "isSupportedCode", - value: function isSupportedCode(code) { - if (this.options.load === 'languageOnly' || this.options.nonExplicitSupportedLngs) { - code = this.getLanguagePartFromCode(code); - } - - return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.indexOf(code) > -1; + ], + glsl: +` _st.y += scrollY + time*speed; + return fract(_st);` +}, +{ + name: 'modulateScrollY', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'scrollY', + default: 0.5, + }, +{ + type: 'float', + name: 'speed', + default: 0, } - }, { - key: "getBestMatchFromCodes", - value: function getBestMatchFromCodes(codes) { - var _this = this; - - if (!codes) return null; - var found; - codes.forEach(function (code) { - if (found) return; - - var cleanedLng = _this.formatLanguageCode(code); - - if (!_this.options.supportedLngs || _this.isSupportedCode(cleanedLng)) found = cleanedLng; - }); - - if (!found && this.options.supportedLngs) { - codes.forEach(function (code) { - if (found) return; - - var lngOnly = _this.getLanguagePartFromCode(code); - - if (_this.isSupportedCode(lngOnly)) return found = lngOnly; - found = _this.options.supportedLngs.find(function (supportedLng) { - if (supportedLng.indexOf(lngOnly) === 0) return supportedLng; - }); - }); - } - - if (!found) found = this.getFallbackCodes(this.options.fallbackLng)[0]; - return found; + ], + glsl: +` _st.y += _c0.r*scrollY + time*speed; + return fract(_st);` +}, +{ + name: 'add', + type: 'combine', + inputs: [ + { + type: 'float', + name: 'amount', + default: 1, } - }, { - key: "getFallbackCodes", - value: function getFallbackCodes(fallbacks, code) { - if (!fallbacks) return []; - if (typeof fallbacks === 'function') fallbacks = fallbacks(code); - if (typeof fallbacks === 'string') fallbacks = [fallbacks]; - if (Object.prototype.toString.apply(fallbacks) === '[object Array]') return fallbacks; - if (!code) return fallbacks["default"] || []; - var found = fallbacks[code]; - if (!found) found = fallbacks[this.getScriptPartFromCode(code)]; - if (!found) found = fallbacks[this.formatLanguageCode(code)]; - if (!found) found = fallbacks[this.getLanguagePartFromCode(code)]; - if (!found) found = fallbacks["default"]; - return found || []; + ], + glsl: +` return (_c0+_c1)*amount + _c0*(1.0-amount);` +}, +{ + name: 'sub', + type: 'combine', + inputs: [ + { + type: 'float', + name: 'amount', + default: 1, } - }, { - key: "toResolveHierarchy", - value: function toResolveHierarchy(code, fallbackCode) { - var _this2 = this; - - var fallbackCodes = this.getFallbackCodes(fallbackCode || this.options.fallbackLng || [], code); - var codes = []; - - var addCode = function addCode(c) { - if (!c) return; - - if (_this2.isSupportedCode(c)) { - codes.push(c); - } else { - _this2.logger.warn("rejecting language code not found in supportedLngs: ".concat(c)); - } - }; - - if (typeof code === 'string' && code.indexOf('-') > -1) { - if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code)); - if (this.options.load !== 'languageOnly' && this.options.load !== 'currentOnly') addCode(this.getScriptPartFromCode(code)); - if (this.options.load !== 'currentOnly') addCode(this.getLanguagePartFromCode(code)); - } else if (typeof code === 'string') { - addCode(this.formatLanguageCode(code)); - } + ], + glsl: +` return (_c0-_c1)*amount + _c0*(1.0-amount);` +}, +{ + name: 'layer', + type: 'combine', + inputs: [ - fallbackCodes.forEach(function (fc) { - if (codes.indexOf(fc) < 0) addCode(_this2.formatLanguageCode(fc)); - }); - return codes; + ], + glsl: +` return vec4(mix(_c0.rgb, _c1.rgb, _c1.a), _c0.a+_c1.a);` +}, +{ + name: 'blend', + type: 'combine', + inputs: [ + { + type: 'float', + name: 'amount', + default: 0.5, } - }]); - - return LanguageUtil; -}(); - -var sets = [{ - lngs: ['ach', 'ak', 'am', 'arn', 'br', 'fil', 'gun', 'ln', 'mfe', 'mg', 'mi', 'oc', 'pt', 'pt-BR', 'tg', 'tl', 'ti', 'tr', 'uz', 'wa'], - nr: [1, 2], - fc: 1 -}, { - lngs: ['af', 'an', 'ast', 'az', 'bg', 'bn', 'ca', 'da', 'de', 'dev', 'el', 'en', 'eo', 'es', 'et', 'eu', 'fi', 'fo', 'fur', 'fy', 'gl', 'gu', 'ha', 'hi', 'hu', 'hy', 'ia', 'it', 'kk', 'kn', 'ku', 'lb', 'mai', 'ml', 'mn', 'mr', 'nah', 'nap', 'nb', 'ne', 'nl', 'nn', 'no', 'nso', 'pa', 'pap', 'pms', 'ps', 'pt-PT', 'rm', 'sco', 'se', 'si', 'so', 'son', 'sq', 'sv', 'sw', 'ta', 'te', 'tk', 'ur', 'yo'], - nr: [1, 2], - fc: 2 -}, { - lngs: ['ay', 'bo', 'cgg', 'fa', 'ht', 'id', 'ja', 'jbo', 'ka', 'km', 'ko', 'ky', 'lo', 'ms', 'sah', 'su', 'th', 'tt', 'ug', 'vi', 'wo', 'zh'], - nr: [1], - fc: 3 -}, { - lngs: ['be', 'bs', 'cnr', 'dz', 'hr', 'ru', 'sr', 'uk'], - nr: [1, 2, 5], - fc: 4 -}, { - lngs: ['ar'], - nr: [0, 1, 2, 3, 11, 100], - fc: 5 -}, { - lngs: ['cs', 'sk'], - nr: [1, 2, 5], - fc: 6 -}, { - lngs: ['csb', 'pl'], - nr: [1, 2, 5], - fc: 7 -}, { - lngs: ['cy'], - nr: [1, 2, 3, 8], - fc: 8 -}, { - lngs: ['fr'], - nr: [1, 2], - fc: 9 -}, { - lngs: ['ga'], - nr: [1, 2, 3, 7, 11], - fc: 10 -}, { - lngs: ['gd'], - nr: [1, 2, 3, 20], - fc: 11 -}, { - lngs: ['is'], - nr: [1, 2], - fc: 12 -}, { - lngs: ['jv'], - nr: [0, 1], - fc: 13 -}, { - lngs: ['kw'], - nr: [1, 2, 3, 4], - fc: 14 -}, { - lngs: ['lt'], - nr: [1, 2, 10], - fc: 15 -}, { - lngs: ['lv'], - nr: [1, 2, 0], - fc: 16 -}, { - lngs: ['mk'], - nr: [1, 2], - fc: 17 -}, { - lngs: ['mnk'], - nr: [0, 1, 2], - fc: 18 -}, { - lngs: ['mt'], - nr: [1, 2, 11, 20], - fc: 19 -}, { - lngs: ['or'], - nr: [2, 1], - fc: 2 -}, { - lngs: ['ro'], - nr: [1, 2, 20], - fc: 20 -}, { - lngs: ['sl'], - nr: [5, 1, 2, 3], - fc: 21 -}, { - lngs: ['he', 'iw'], - nr: [1, 2, 20, 21], - fc: 22 -}]; -var _rulesPluralsTypes = { - 1: function _(n) { - return Number(n > 1); - }, - 2: function _(n) { - return Number(n != 1); - }, - 3: function _(n) { - return 0; - }, - 4: function _(n) { - return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); - }, - 5: function _(n) { - return Number(n == 0 ? 0 : n == 1 ? 1 : n == 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5); - }, - 6: function _(n) { - return Number(n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2); - }, - 7: function _(n) { - return Number(n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); - }, - 8: function _(n) { - return Number(n == 1 ? 0 : n == 2 ? 1 : n != 8 && n != 11 ? 2 : 3); - }, - 9: function _(n) { - return Number(n >= 2); - }, - 10: function _(n) { - return Number(n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4); - }, - 11: function _(n) { - return Number(n == 1 || n == 11 ? 0 : n == 2 || n == 12 ? 1 : n > 2 && n < 20 ? 2 : 3); - }, - 12: function _(n) { - return Number(n % 10 != 1 || n % 100 == 11); - }, - 13: function _(n) { - return Number(n !== 0); - }, - 14: function _(n) { - return Number(n == 1 ? 0 : n == 2 ? 1 : n == 3 ? 2 : 3); - }, - 15: function _(n) { - return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); - }, - 16: function _(n) { - return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n !== 0 ? 1 : 2); - }, - 17: function _(n) { - return Number(n == 1 || n % 10 == 1 && n % 100 != 11 ? 0 : 1); - }, - 18: function _(n) { - return Number(n == 0 ? 0 : n == 1 ? 1 : 2); - }, - 19: function _(n) { - return Number(n == 1 ? 0 : n == 0 || n % 100 > 1 && n % 100 < 11 ? 1 : n % 100 > 10 && n % 100 < 20 ? 2 : 3); - }, - 20: function _(n) { - return Number(n == 1 ? 0 : n == 0 || n % 100 > 0 && n % 100 < 20 ? 1 : 2); - }, - 21: function _(n) { - return Number(n % 100 == 1 ? 1 : n % 100 == 2 ? 2 : n % 100 == 3 || n % 100 == 4 ? 3 : 0); - }, - 22: function _(n) { - return Number(n == 1 ? 0 : n == 2 ? 1 : (n < 0 || n > 10) && n % 10 == 0 ? 2 : 3); - } -}; -var deprecatedJsonVersions = ['v1', 'v2', 'v3']; -var suffixesOrder = { - zero: 0, - one: 1, - two: 2, - few: 3, - many: 4, - other: 5 -}; - -function createRules() { - var rules = {}; - sets.forEach(function (set) { - set.lngs.forEach(function (l) { - rules[l] = { - numbers: set.nr, - plurals: _rulesPluralsTypes[set.fc] - }; - }); - }); - return rules; -} - -var PluralResolver = function () { - function PluralResolver(languageUtils) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - _classCallCheck__default['default'](this, PluralResolver); - - this.languageUtils = languageUtils; - this.options = options; - this.logger = baseLogger.create('pluralResolver'); - - if ((!this.options.compatibilityJSON || this.options.compatibilityJSON === 'v4') && (typeof Intl === 'undefined' || !Intl.PluralRules)) { - this.options.compatibilityJSON = 'v3'; - this.logger.error('Your environment seems not to be Intl API compatible, use an Intl.PluralRules polyfill. Will fallback to the compatibilityJSON v3 format handling.'); + ], + glsl: +` return _c0*(1.0-amount)+_c1*amount;` +}, +{ + name: 'mult', + type: 'combine', + inputs: [ + { + type: 'float', + name: 'amount', + default: 1, } + ], + glsl: +` return _c0*(1.0-amount)+(_c0*_c1)*amount;` +}, +{ + name: 'diff', + type: 'combine', + inputs: [ - this.rules = createRules(); - } - - _createClass__default['default'](PluralResolver, [{ - key: "addRule", - value: function addRule(lng, obj) { - this.rules[lng] = obj; + ], + glsl: +` return vec4(abs(_c0.rgb-_c1.rgb), max(_c0.a, _c1.a));` +}, +{ + name: 'modulate', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'amount', + default: 0.1, } - }, { - key: "getRule", - value: function getRule(code) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - if (this.shouldUseIntlApi()) { - try { - return new Intl.PluralRules(code, { - type: options.ordinal ? 'ordinal' : 'cardinal' - }); - } catch (_unused) { - return; - } - } - - return this.rules[code] || this.rules[this.languageUtils.getLanguagePartFromCode(code)]; + ], + glsl: +` // return fract(st+(_c0.xy-0.5)*amount); + return _st + _c0.xy*amount;` +}, +{ + name: 'modulateScale', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'multiple', + default: 1, + }, +{ + type: 'float', + name: 'offset', + default: 1, } - }, { - key: "needsPlural", - value: function needsPlural(code) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var rule = this.getRule(code, options); - - if (this.shouldUseIntlApi()) { - return rule && rule.resolvedOptions().pluralCategories.length > 1; - } - - return rule && rule.numbers.length > 1; + ], + glsl: +` vec2 xy = _st - vec2(0.5); + xy*=(1.0/vec2(offset + multiple*_c0.r, offset + multiple*_c0.g)); + xy+=vec2(0.5); + return xy;` +}, +{ + name: 'modulatePixelate', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'multiple', + default: 10, + }, +{ + type: 'float', + name: 'offset', + default: 3, } - }, { - key: "getPluralFormsOfKey", - value: function getPluralFormsOfKey(code, key) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - return this.getSuffixes(code, options).map(function (suffix) { - return "".concat(key).concat(suffix); - }); + ], + glsl: +` vec2 xy = vec2(offset + _c0.x*multiple, offset + _c0.y*multiple); + return (floor(_st * xy) + 0.5)/xy;` +}, +{ + name: 'modulateRotate', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'multiple', + default: 1, + }, +{ + type: 'float', + name: 'offset', + default: 0, } - }, { - key: "getSuffixes", - value: function getSuffixes(code) { - var _this = this; - - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var rule = this.getRule(code, options); - - if (!rule) { - return []; - } - - if (this.shouldUseIntlApi()) { - return rule.resolvedOptions().pluralCategories.sort(function (pluralCategory1, pluralCategory2) { - return suffixesOrder[pluralCategory1] - suffixesOrder[pluralCategory2]; - }).map(function (pluralCategory) { - return "".concat(_this.options.prepend).concat(pluralCategory); - }); - } - - return rule.numbers.map(function (number) { - return _this.getSuffix(code, number, options); - }); + ], + glsl: +` vec2 xy = _st - vec2(0.5); + float angle = offset + _c0.x * multiple; + xy = mat2(cos(angle),-sin(angle), sin(angle),cos(angle))*xy; + xy += 0.5; + return xy;` +}, +{ + name: 'modulateHue', + type: 'combineCoord', + inputs: [ + { + type: 'float', + name: 'amount', + default: 1, } - }, { - key: "getSuffix", - value: function getSuffix(code, count) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - var rule = this.getRule(code, options); - - if (rule) { - if (this.shouldUseIntlApi()) { - return "".concat(this.options.prepend).concat(rule.select(count)); - } - - return this.getSuffixRetroCompatible(rule, count); - } - - this.logger.warn("no plural rule found for: ".concat(code)); - return ''; + ], + glsl: +` return _st + (vec2(_c0.g - _c0.r, _c0.b - _c0.g) * amount * 1.0/resolution);` +}, +{ + name: 'invert', + type: 'color', + inputs: [ + { + type: 'float', + name: 'amount', + default: 1, } - }, { - key: "getSuffixRetroCompatible", - value: function getSuffixRetroCompatible(rule, count) { - var _this2 = this; - - var idx = rule.noAbs ? rule.plurals(count) : rule.plurals(Math.abs(count)); - var suffix = rule.numbers[idx]; - - if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) { - if (suffix === 2) { - suffix = 'plural'; - } else if (suffix === 1) { - suffix = ''; - } - } - - var returnSuffix = function returnSuffix() { - return _this2.options.prepend && suffix.toString() ? _this2.options.prepend + suffix.toString() : suffix.toString(); - }; - - if (this.options.compatibilityJSON === 'v1') { - if (suffix === 1) return ''; - if (typeof suffix === 'number') return "_plural_".concat(suffix.toString()); - return returnSuffix(); - } else if (this.options.compatibilityJSON === 'v2') { - return returnSuffix(); - } else if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) { - return returnSuffix(); - } - - return this.options.prepend && idx.toString() ? this.options.prepend + idx.toString() : idx.toString(); + ], + glsl: +` return vec4((1.0-_c0.rgb)*amount + _c0.rgb*(1.0-amount), _c0.a);` +}, +{ + name: 'contrast', + type: 'color', + inputs: [ + { + type: 'float', + name: 'amount', + default: 1.6, } - }, { - key: "shouldUseIntlApi", - value: function shouldUseIntlApi() { - return !deprecatedJsonVersions.includes(this.options.compatibilityJSON); + ], + glsl: +` vec4 c = (_c0-vec4(0.5))*vec4(amount) + vec4(0.5); + return vec4(c.rgb, _c0.a);` +}, +{ + name: 'brightness', + type: 'color', + inputs: [ + { + type: 'float', + name: 'amount', + default: 0.4, } - }]); - - return PluralResolver; -}(); - -function ownKeys$3(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread$3(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$3(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$3(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - -var Interpolator = function () { - function Interpolator() { - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck__default['default'](this, Interpolator); - - this.logger = baseLogger.create('interpolator'); - this.options = options; - - this.format = options.interpolation && options.interpolation.format || function (value) { - return value; - }; + ], + glsl: +` return vec4(_c0.rgb + vec3(amount), _c0.a);` +}, +{ + name: 'mask', + type: 'combine', + inputs: [ - this.init(options); - } + ], + glsl: + ` float a = _luminance(_c1.rgb); + return vec4(_c0.rgb*a, a*_c0.a);` +}, - _createClass__default['default'](Interpolator, [{ - key: "init", - value: function init() { - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - if (!options.interpolation) options.interpolation = { - escapeValue: true - }; - var iOpts = options.interpolation; - this.escape = iOpts.escape !== undefined ? iOpts.escape : escape; - this.escapeValue = iOpts.escapeValue !== undefined ? iOpts.escapeValue : true; - this.useRawValueToEscape = iOpts.useRawValueToEscape !== undefined ? iOpts.useRawValueToEscape : false; - this.prefix = iOpts.prefix ? regexEscape(iOpts.prefix) : iOpts.prefixEscaped || '{{'; - this.suffix = iOpts.suffix ? regexEscape(iOpts.suffix) : iOpts.suffixEscaped || '}}'; - this.formatSeparator = iOpts.formatSeparator ? iOpts.formatSeparator : iOpts.formatSeparator || ','; - this.unescapePrefix = iOpts.unescapeSuffix ? '' : iOpts.unescapePrefix || '-'; - this.unescapeSuffix = this.unescapePrefix ? '' : iOpts.unescapeSuffix || ''; - this.nestingPrefix = iOpts.nestingPrefix ? regexEscape(iOpts.nestingPrefix) : iOpts.nestingPrefixEscaped || regexEscape('$t('); - this.nestingSuffix = iOpts.nestingSuffix ? regexEscape(iOpts.nestingSuffix) : iOpts.nestingSuffixEscaped || regexEscape(')'); - this.nestingOptionsSeparator = iOpts.nestingOptionsSeparator ? iOpts.nestingOptionsSeparator : iOpts.nestingOptionsSeparator || ','; - this.maxReplaces = iOpts.maxReplaces ? iOpts.maxReplaces : 1000; - this.alwaysFormat = iOpts.alwaysFormat !== undefined ? iOpts.alwaysFormat : false; - this.resetRegExp(); +{ + name: 'luma', + type: 'color', + inputs: [ + { + type: 'float', + name: 'threshold', + default: 0.5, + }, +{ + type: 'float', + name: 'tolerance', + default: 0.1, } - }, { - key: "reset", - value: function reset() { - if (this.options) this.init(this.options); + ], + glsl: +` float a = smoothstep(threshold-(tolerance+0.0000001), threshold+(tolerance+0.0000001), _luminance(_c0.rgb)); + return vec4(_c0.rgb*a, a);` +}, +{ + name: 'thresh', + type: 'color', + inputs: [ + { + type: 'float', + name: 'threshold', + default: 0.5, + }, +{ + type: 'float', + name: 'tolerance', + default: 0.04, } - }, { - key: "resetRegExp", - value: function resetRegExp() { - var regexpStr = "".concat(this.prefix, "(.+?)").concat(this.suffix); - this.regexp = new RegExp(regexpStr, 'g'); - var regexpUnescapeStr = "".concat(this.prefix).concat(this.unescapePrefix, "(.+?)").concat(this.unescapeSuffix).concat(this.suffix); - this.regexpUnescape = new RegExp(regexpUnescapeStr, 'g'); - var nestingRegexpStr = "".concat(this.nestingPrefix, "(.+?)").concat(this.nestingSuffix); - this.nestingRegexp = new RegExp(nestingRegexpStr, 'g'); + ], + glsl: +` return vec4(vec3(smoothstep(threshold-(tolerance+0.0000001), threshold+(tolerance+0.0000001), _luminance(_c0.rgb))), _c0.a);` +}, +{ + name: 'color', + type: 'color', + inputs: [ + { + type: 'float', + name: 'r', + default: 1, + }, +{ + type: 'float', + name: 'g', + default: 1, + }, +{ + type: 'float', + name: 'b', + default: 1, + }, +{ + type: 'float', + name: 'a', + default: 1, } - }, { - key: "interpolate", - value: function interpolate(str, data, lng, options) { - var _this = this; - - var match; - var value; - var replaces; - var defaultData = this.options && this.options.interpolation && this.options.interpolation.defaultVariables || {}; - - function regexSafe(val) { - return val.replace(/\$/g, '$$$$'); - } - - var handleFormat = function handleFormat(key) { - if (key.indexOf(_this.formatSeparator) < 0) { - var path = getPathWithDefaults(data, defaultData, key); - return _this.alwaysFormat ? _this.format(path, undefined, lng, _objectSpread$3(_objectSpread$3(_objectSpread$3({}, options), data), {}, { - interpolationkey: key - })) : path; - } - - var p = key.split(_this.formatSeparator); - var k = p.shift().trim(); - var f = p.join(_this.formatSeparator).trim(); - return _this.format(getPathWithDefaults(data, defaultData, k), f, lng, _objectSpread$3(_objectSpread$3(_objectSpread$3({}, options), data), {}, { - interpolationkey: k - })); - }; - - this.resetRegExp(); - var missingInterpolationHandler = options && options.missingInterpolationHandler || this.options.missingInterpolationHandler; - var skipOnVariables = options && options.interpolation && options.interpolation.skipOnVariables !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables; - var todos = [{ - regex: this.regexpUnescape, - safeValue: function safeValue(val) { - return regexSafe(val); - } - }, { - regex: this.regexp, - safeValue: function safeValue(val) { - return _this.escapeValue ? regexSafe(_this.escape(val)) : regexSafe(val); - } - }]; - todos.forEach(function (todo) { - replaces = 0; - - while (match = todo.regex.exec(str)) { - var matchedVar = match[1].trim(); - value = handleFormat(matchedVar); - - if (value === undefined) { - if (typeof missingInterpolationHandler === 'function') { - var temp = missingInterpolationHandler(str, match, options); - value = typeof temp === 'string' ? temp : ''; - } else if (options && options.hasOwnProperty(matchedVar)) { - value = ''; - } else if (skipOnVariables) { - value = match[0]; - continue; - } else { - _this.logger.warn("missed to pass in variable ".concat(matchedVar, " for interpolating ").concat(str)); - - value = ''; - } - } else if (typeof value !== 'string' && !_this.useRawValueToEscape) { - value = makeString(value); - } - - var safeValue = todo.safeValue(value); - str = str.replace(match[0], safeValue); - - if (skipOnVariables) { - todo.regex.lastIndex += safeValue.length; - todo.regex.lastIndex -= match[0].length; - } else { - todo.regex.lastIndex = 0; - } - - replaces++; - - if (replaces >= _this.maxReplaces) { - break; - } - } - }); - return str; + ], + glsl: +` vec4 c = vec4(r, g, b, a); + vec4 pos = step(0.0, c); // detect whether negative + // if > 0, return r * _c0 + // if < 0 return (1.0-r) * _c0 + return vec4(mix((1.0-_c0)*abs(c), c*_c0, pos));` +}, +{ + name: 'saturate', + type: 'color', + inputs: [ + { + type: 'float', + name: 'amount', + default: 2, } - }, { - key: "nest", - value: function nest(str, fc) { - var _this2 = this; - - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - var match; - var value; - - var clonedOptions = _objectSpread$3({}, options); - - clonedOptions.applyPostProcessor = false; - delete clonedOptions.defaultValue; - - function handleHasOptions(key, inheritedOptions) { - var sep = this.nestingOptionsSeparator; - if (key.indexOf(sep) < 0) return key; - var c = key.split(new RegExp("".concat(sep, "[ ]*{"))); - var optionsString = "{".concat(c[1]); - key = c[0]; - optionsString = this.interpolate(optionsString, clonedOptions); - optionsString = optionsString.replace(/'/g, '"'); - - try { - clonedOptions = JSON.parse(optionsString); - if (inheritedOptions) clonedOptions = _objectSpread$3(_objectSpread$3({}, inheritedOptions), clonedOptions); - } catch (e) { - this.logger.warn("failed parsing options string in nesting for key ".concat(key), e); - return "".concat(key).concat(sep).concat(optionsString); - } - - delete clonedOptions.defaultValue; - return key; - } - - while (match = this.nestingRegexp.exec(str)) { - var formatters = []; - var doReduce = false; - - if (match[0].indexOf(this.formatSeparator) !== -1 && !/{.*}/.test(match[1])) { - var r = match[1].split(this.formatSeparator).map(function (elem) { - return elem.trim(); - }); - match[1] = r.shift(); - formatters = r; - doReduce = true; - } - - value = fc(handleHasOptions.call(this, match[1].trim(), clonedOptions), clonedOptions); - if (value && match[0] === str && typeof value !== 'string') return value; - if (typeof value !== 'string') value = makeString(value); - - if (!value) { - this.logger.warn("missed to resolve ".concat(match[1], " for nesting ").concat(str)); - value = ''; - } - - if (doReduce) { - value = formatters.reduce(function (v, f) { - return _this2.format(v, f, options.lng, _objectSpread$3(_objectSpread$3({}, options), {}, { - interpolationkey: match[1].trim() - })); - }, value.trim()); - } - - str = str.replace(match[0], value); - this.regexp.lastIndex = 0; - } - - return str; + ], + glsl: +` const vec3 W = vec3(0.2125, 0.7154, 0.0721); + vec3 intensity = vec3(dot(_c0.rgb, W)); + return vec4(mix(intensity, _c0.rgb, amount), _c0.a);` +}, +{ + name: 'hue', + type: 'color', + inputs: [ + { + type: 'float', + name: 'hue', + default: 0.4, } - }]); - - return Interpolator; -}(); - -function ownKeys$4(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread$4(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$4(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$4(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - -function parseFormatStr(formatStr) { - var formatName = formatStr.toLowerCase().trim(); - var formatOptions = {}; - - if (formatStr.indexOf('(') > -1) { - var p = formatStr.split('('); - formatName = p[0].toLowerCase().trim(); - var optStr = p[1].substring(0, p[1].length - 1); - - if (formatName === 'currency' && optStr.indexOf(':') < 0) { - if (!formatOptions.currency) formatOptions.currency = optStr.trim(); - } else if (formatName === 'relativetime' && optStr.indexOf(':') < 0) { - if (!formatOptions.range) formatOptions.range = optStr.trim(); - } else { - var opts = optStr.split(';'); - opts.forEach(function (opt) { - if (!opt) return; - - var _opt$split = opt.split(':'), - _opt$split2 = _toArray__default['default'](_opt$split), - key = _opt$split2[0], - rest = _opt$split2.slice(1); - - var val = rest.join(':'); - if (val.trim() === 'false') formatOptions[key.trim()] = false; - if (val.trim() === 'true') formatOptions[key.trim()] = true; - if (!isNaN(val.trim())) formatOptions[key.trim()] = parseInt(val.trim(), 10); - if (!formatOptions[key.trim()]) formatOptions[key.trim()] = val.trim(); - }); + ], + glsl: +` vec3 c = _rgbToHsv(_c0.rgb); + c.r += hue; + // c.r = fract(c.r); + return vec4(_hsvToRgb(c), _c0.a);` +}, +{ + name: 'colorama', + type: 'color', + inputs: [ + { + type: 'float', + name: 'amount', + default: 0.005, } - } - - return { - formatName: formatName, - formatOptions: formatOptions - }; -} - -var Formatter = function () { - function Formatter() { - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck__default['default'](this, Formatter); - - this.logger = baseLogger.create('formatter'); - this.options = options; - this.formats = { - number: function number(val, lng, options) { - return new Intl.NumberFormat(lng, options).format(val); - }, - currency: function currency(val, lng, options) { - return new Intl.NumberFormat(lng, _objectSpread$4(_objectSpread$4({}, options), {}, { - style: 'currency' - })).format(val); - }, - datetime: function datetime(val, lng, options) { - return new Intl.DateTimeFormat(lng, _objectSpread$4({}, options)).format(val); - }, - relativetime: function relativetime(val, lng, options) { - return new Intl.RelativeTimeFormat(lng, _objectSpread$4({}, options)).format(val, options.range || 'day'); - }, - list: function list(val, lng, options) { - return new Intl.ListFormat(lng, _objectSpread$4({}, options)).format(val); - } - }; - this.init(options); - } + ], + glsl: +` vec3 c = _rgbToHsv(_c0.rgb); + c += vec3(amount); + c = _hsvToRgb(c); + c = fract(c); + return vec4(c, _c0.a);` +}, +{ + name: 'prev', + type: 'src', + inputs: [ - _createClass__default['default'](Formatter, [{ - key: "init", - value: function init(services) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { - interpolation: {} - }; - var iOpts = options.interpolation; - this.formatSeparator = iOpts.formatSeparator ? iOpts.formatSeparator : iOpts.formatSeparator || ','; + ], + glsl: +` return texture2D(prevBuffer, fract(_st));` +}, +{ + name: 'sum', + type: 'color', + inputs: [ + { + type: 'vec4', + name: 'scale', + default: 1, } - }, { - key: "add", - value: function add(name, fc) { - this.formats[name.toLowerCase().trim()] = fc; + ], + glsl: +` vec4 v = _c0 * s; + return v.r + v.g + v.b + v.a; + } + float sum(vec2 _st, vec4 s) { // vec4 is not a typo, because argument type is not overloaded + vec2 v = _st.xy * s.xy; + return v.x + v.y;` +}, +{ + name: 'r', + type: 'color', + inputs: [ + { + type: 'float', + name: 'scale', + default: 1, + }, +{ + type: 'float', + name: 'offset', + default: 0, } - }, { - key: "format", - value: function format(value, _format, lng, options) { - var _this = this; - - var formats = _format.split(this.formatSeparator); - - var result = formats.reduce(function (mem, f) { - var _parseFormatStr = parseFormatStr(f), - formatName = _parseFormatStr.formatName, - formatOptions = _parseFormatStr.formatOptions; - - if (_this.formats[formatName]) { - var formatted = mem; - - try { - var valOptions = options && options.formatParams && options.formatParams[options.interpolationkey] || {}; - var l = valOptions.locale || valOptions.lng || options.locale || options.lng || lng; - formatted = _this.formats[formatName](mem, l, _objectSpread$4(_objectSpread$4(_objectSpread$4({}, formatOptions), options), valOptions)); - } catch (error) { - _this.logger.warn(error); - } - - return formatted; - } else { - _this.logger.warn("there was no format function for ".concat(formatName)); - } - - return mem; - }, value); - return result; + ], + glsl: +` return vec4(_c0.r * scale + offset);` +}, +{ + name: 'g', + type: 'color', + inputs: [ + { + type: 'float', + name: 'scale', + default: 1, + }, +{ + type: 'float', + name: 'offset', + default: 0, } - }]); + ], + glsl: +` return vec4(_c0.g * scale + offset);` +}, +{ + name: 'b', + type: 'color', + inputs: [ + { + type: 'float', + name: 'scale', + default: 1, + }, +{ + type: 'float', + name: 'offset', + default: 0, + } + ], + glsl: +` return vec4(_c0.b * scale + offset);` +}, +{ + name: 'a', + type: 'color', + inputs: [ + { + type: 'float', + name: 'scale', + default: 1, + }, +{ + type: 'float', + name: 'offset', + default: 0, + } + ], + glsl: +` return vec4(_c0.a * scale + offset);` +} +] - return Formatter; -}(); +},{}],74:[function(require,module,exports){ +// functions that are only used within other functions -function ownKeys$5(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } +module.exports = { + _luminance: { + type: 'util', + glsl: `float _luminance(vec3 rgb){ + const vec3 W = vec3(0.2125, 0.7154, 0.0721); + return dot(rgb, W); + }` + }, + _noise: { + type: 'util', + glsl: ` + // Simplex 3D Noise + // by Ian McEwan, Ashima Arts + vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);} + vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} -function _objectSpread$5(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$5(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$5(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + float _noise(vec3 v){ + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); -function _createSuper$2(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$2(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } + // First corner + vec3 i = floor(v + dot(v, C.yyy) ); + vec3 x0 = v - i + dot(i, C.xxx) ; -function _isNativeReflectConstruct$2() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); -function remove(arr, what) { - var found = arr.indexOf(what); + // x0 = x0 - 0. + 0.0 * C + vec3 x1 = x0 - i1 + 1.0 * C.xxx; + vec3 x2 = x0 - i2 + 2.0 * C.xxx; + vec3 x3 = x0 - 1. + 3.0 * C.xxx; - while (found !== -1) { - arr.splice(found, 1); - found = arr.indexOf(what); - } -} + // Permutations + i = mod(i, 289.0 ); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); -var Connector = function (_EventEmitter) { - _inherits__default['default'](Connector, _EventEmitter); + // Gradients + // ( N*N points uniformly over a square, mapped onto an octahedron.) + float n_ = 1.0/7.0; // N=7 + vec3 ns = n_ * D.wyz - D.xzx; - var _super = _createSuper$2(Connector); + vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) - function Connector(backend, store, services) { - var _this; + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) - var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); - _classCallCheck__default['default'](this, Connector); + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); - _this = _super.call(this); + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); - if (isIE10) { - EventEmitter.call(_assertThisInitialized__default['default'](_this)); - } + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; - _this.backend = backend; - _this.store = store; - _this.services = services; - _this.languageUtils = services.languageUtils; - _this.options = options; - _this.logger = baseLogger.create('backendConnector'); - _this.state = {}; - _this.queue = []; + vec3 p0 = vec3(a0.xy,h.x); + vec3 p1 = vec3(a0.zw,h.y); + vec3 p2 = vec3(a1.xy,h.z); + vec3 p3 = vec3(a1.zw,h.w); - if (_this.backend && _this.backend.init) { - _this.backend.init(services, options.backend, options); - } + //Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; - return _this; + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + dot(p2,x2), dot(p3,x3) ) ); } + ` + }, - _createClass__default['default'](Connector, [{ - key: "queueLoad", - value: function queueLoad(languages, namespaces, options, callback) { - var _this2 = this; - - var toLoad = []; - var pending = []; - var toLoadLanguages = []; - var toLoadNamespaces = []; - languages.forEach(function (lng) { - var hasAllNamespaces = true; - namespaces.forEach(function (ns) { - var name = "".concat(lng, "|").concat(ns); - - if (!options.reload && _this2.store.hasResourceBundle(lng, ns)) { - _this2.state[name] = 2; - } else if (_this2.state[name] < 0) ; else if (_this2.state[name] === 1) { - if (pending.indexOf(name) < 0) pending.push(name); - } else { - _this2.state[name] = 1; - hasAllNamespaces = false; - if (pending.indexOf(name) < 0) pending.push(name); - if (toLoad.indexOf(name) < 0) toLoad.push(name); - if (toLoadNamespaces.indexOf(ns) < 0) toLoadNamespaces.push(ns); - } - }); - if (!hasAllNamespaces) toLoadLanguages.push(lng); - }); - - if (toLoad.length || pending.length) { - this.queue.push({ - pending: pending, - loaded: {}, - errors: [], - callback: callback - }); - } - - return { - toLoad: toLoad, - pending: pending, - toLoadLanguages: toLoadLanguages, - toLoadNamespaces: toLoadNamespaces - }; - } - }, { - key: "loaded", - value: function loaded(name, err, data) { - var s = name.split('|'); - var lng = s[0]; - var ns = s[1]; - if (err) this.emit('failedLoading', lng, ns, err); - - if (data) { - this.store.addResourceBundle(lng, ns, data); - } - - this.state[name] = err ? -1 : 2; - var loaded = {}; - this.queue.forEach(function (q) { - pushPath(q.loaded, [lng], ns); - remove(q.pending, name); - if (err) q.errors.push(err); - if (q.pending.length === 0 && !q.done) { - Object.keys(q.loaded).forEach(function (l) { - if (!loaded[l]) loaded[l] = []; + _rgbToHsv: { + type: 'util', + glsl: `vec3 _rgbToHsv(vec3 c){ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - if (q.loaded[l].length) { - q.loaded[l].forEach(function (ns) { - if (loaded[l].indexOf(ns) < 0) loaded[l].push(ns); - }); - } - }); - q.done = true; + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); + }` + }, + _hsvToRgb: { + type: 'util', + glsl: `vec3 _hsvToRgb(vec3 c){ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + }` + } +} - if (q.errors.length) { - q.callback(q.errors); - } else { - q.callback(); - } - } - }); - this.emit('loaded', loaded); - this.queue = this.queue.filter(function (q) { - return !q.done; - }); - } - }, { - key: "read", - value: function read(lng, ns, fcName) { - var _this3 = this; +},{}],75:[function(require,module,exports){ +const Webcam = require('./lib/webcam.js') +const Screen = require('./lib/screenmedia.js') - var tried = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; - var wait = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 350; - var callback = arguments.length > 5 ? arguments[5] : undefined; - if (!lng.length) return callback(null, {}); - return this.backend[fcName](lng, ns, function (err, data) { - if (err && data && tried < 5) { - setTimeout(function () { - _this3.read.call(_this3, lng, ns, fcName, tried + 1, wait * 2, callback); - }, wait); - return; - } +class HydraSource { + constructor ({ regl, width, height, pb, label = ""}) { + this.label = label + this.regl = regl + this.src = null + this.dynamic = true + this.width = width + this.height = height + this.tex = this.regl.texture({ + // shape: [width, height] + shape: [ 1, 1 ] + }) + this.pb = pb + } - callback(err, data); - }); + init (opts) { + if (opts.src) { + this.src = opts.src + this.tex = this.regl.texture(this.src) } - }, { - key: "prepareLoading", - value: function prepareLoading(languages, namespaces) { - var _this4 = this; - - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - var callback = arguments.length > 3 ? arguments[3] : undefined; - - if (!this.backend) { - this.logger.warn('No backend was added via i18next.use. Will not load resources.'); - return callback && callback(); - } + if (opts.dynamic) this.dynamic = opts.dynamic + } - if (typeof languages === 'string') languages = this.languageUtils.toResolveHierarchy(languages); - if (typeof namespaces === 'string') namespaces = [namespaces]; - var toLoad = this.queueLoad(languages, namespaces, options, callback); + initCam (index) { + const self = this + Webcam(index) + .then(response => { + self.src = response.video + self.dynamic = true + self.tex = self.regl.texture(self.src) + }) + .catch(err => console.log('could not get camera', err)) + } - if (!toLoad.toLoad.length) { - if (!toLoad.pending.length) callback(); - return null; - } + initVideo (url = '') { + // const self = this + const vid = document.createElement('video') + vid.crossOrigin = 'anonymous' + vid.autoplay = true + vid.loop = true + vid.muted = true // mute in order to load without user interaction + const onload = vid.addEventListener('loadeddata', () => { + this.src = vid + vid.play() + this.tex = this.regl.texture(this.src) + this.dynamic = true + }) + vid.src = url + } - toLoad.toLoad.forEach(function (name) { - _this4.loadOne(name); - }); - } - }, { - key: "load", - value: function load(languages, namespaces, callback) { - this.prepareLoading(languages, namespaces, {}, callback); - } - }, { - key: "reload", - value: function reload(languages, namespaces, callback) { - this.prepareLoading(languages, namespaces, { - reload: true - }, callback); + initImage (url = '') { + const img = document.createElement('img') + img.crossOrigin = 'anonymous' + img.src = url + img.onload = () => { + this.src = img + this.dynamic = false + this.tex = this.regl.texture(this.src) } - }, { - key: "loadOne", - value: function loadOne(name) { - var _this5 = this; + } - var prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; - var s = name.split('|'); - var lng = s[0]; - var ns = s[1]; - this.read(lng, ns, 'read', undefined, undefined, function (err, data) { - if (err) _this5.logger.warn("".concat(prefix, "loading namespace ").concat(ns, " for language ").concat(lng, " failed"), err); - if (!err && data) _this5.logger.log("".concat(prefix, "loaded namespace ").concat(ns, " for language ").concat(lng), data); + initStream (streamName) { + // console.log("initing stream!", streamName) + let self = this + if (streamName && this.pb) { + this.pb.initSource(streamName) - _this5.loaded(name, err, data); - }); + this.pb.on('got video', function (nick, video) { + if (nick === streamName) { + self.src = video + self.dynamic = true + self.tex = self.regl.texture(self.src) + } + }) } - }, { - key: "saveMissing", - value: function saveMissing(languages, namespace, key, fallbackValue, isUpdate) { - var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; + } - if (this.services.utils && this.services.utils.hasLoadedNamespace && !this.services.utils.hasLoadedNamespace(namespace)) { - this.logger.warn("did not save key \"".concat(key, "\" as the namespace \"").concat(namespace, "\" was not yet loaded"), 'This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!'); - return; - } + initScreen () { + const self = this + Screen() + .then(function (response) { + self.src = response.video + self.tex = self.regl.texture(self.src) + self.dynamic = true + // console.log("received screen input") + }) + .catch(err => console.log('could not get screen', err)) + } - if (key === undefined || key === null || key === '') return; + resize (width, height) { + this.width = width + this.height = height + } - if (this.backend && this.backend.create) { - this.backend.create(languages, namespace, key, fallbackValue, null, _objectSpread$5(_objectSpread$5({}, options), {}, { - isUpdate: isUpdate - })); + clear () { + if (this.src && this.src.srcObject) { + if (this.src.srcObject.getTracks) { + this.src.srcObject.getTracks().forEach(track => track.stop()) } - - if (!languages || !languages[0]) return; - this.store.addResource(languages[0], namespace, key, fallbackValue); } - }]); - - return Connector; -}(EventEmitter); + this.src = null + this.tex = this.regl.texture({ shape: [ 1, 1 ] }) + } -function get() { - return { - debug: false, - initImmediate: true, - ns: ['translation'], - defaultNS: ['translation'], - fallbackLng: ['dev'], - fallbackNS: false, - supportedLngs: false, - nonExplicitSupportedLngs: false, - load: 'all', - preload: false, - simplifyPluralSuffix: true, - keySeparator: '.', - nsSeparator: ':', - pluralSeparator: '_', - contextSeparator: '_', - partialBundledLanguages: false, - saveMissing: false, - updateMissing: false, - saveMissingTo: 'fallback', - saveMissingPlurals: true, - missingKeyHandler: false, - missingInterpolationHandler: false, - postProcess: false, - postProcessPassResolved: false, - returnNull: true, - returnEmptyString: true, - returnObjects: false, - joinArrays: false, - returnedObjectHandler: false, - parseMissingKeyHandler: false, - appendNamespaceToMissingKey: false, - appendNamespaceToCIMode: false, - overloadTranslationOptionHandler: function handle(args) { - var ret = {}; - if (_typeof__default['default'](args[1]) === 'object') ret = args[1]; - if (typeof args[1] === 'string') ret.defaultValue = args[1]; - if (typeof args[2] === 'string') ret.tDescription = args[2]; + tick (time) { + // console.log(this.src, this.tex.width, this.tex.height) + if (this.src !== null && this.dynamic === true) { + if (this.src.videoWidth && this.src.videoWidth !== this.tex.width) { + console.log( + this.src.videoWidth, + this.src.videoHeight, + this.tex.width, + this.tex.height + ) + this.tex.resize(this.src.videoWidth, this.src.videoHeight) + } - if (_typeof__default['default'](args[2]) === 'object' || _typeof__default['default'](args[3]) === 'object') { - var options = args[3] || args[2]; - Object.keys(options).forEach(function (key) { - ret[key] = options[key]; - }); + if (this.src.width && this.src.width !== this.tex.width) { + this.tex.resize(this.src.width, this.src.height) } - return ret; - }, - interpolation: { - escapeValue: true, - format: function format(value, _format, lng, options) { - return value; - }, - prefix: '{{', - suffix: '}}', - formatSeparator: ',', - unescapePrefix: '-', - nestingPrefix: '$t(', - nestingSuffix: ')', - nestingOptionsSeparator: ',', - maxReplaces: 1000, - skipOnVariables: true + this.tex.subimage(this.src) } - }; -} -function transformOptions(options) { - if (typeof options.ns === 'string') options.ns = [options.ns]; - if (typeof options.fallbackLng === 'string') options.fallbackLng = [options.fallbackLng]; - if (typeof options.fallbackNS === 'string') options.fallbackNS = [options.fallbackNS]; - - if (options.supportedLngs && options.supportedLngs.indexOf('cimode') < 0) { - options.supportedLngs = options.supportedLngs.concat(['cimode']); } - return options; + getTexture () { + return this.tex + } } -function ownKeys$6(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread$6(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$6(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$6(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - -function _createSuper$3(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$3(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } +module.exports = HydraSource -function _isNativeReflectConstruct$3() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +},{"./lib/screenmedia.js":82,"./lib/webcam.js":84}],76:[function(require,module,exports){ +// WIP utils for working with arrays +// Possibly should be integrated with lfo extension, etc. +// to do: transform time rather than array values, similar to working with coordinates in hydra -function noop() {} +var easing = require('./easing-functions.js') -function bindMemberFunctions(inst) { - var mems = Object.getOwnPropertyNames(Object.getPrototypeOf(inst)); - mems.forEach(function (mem) { - if (typeof inst[mem] === 'function') { - inst[mem] = inst[mem].bind(inst); - } - }); +var map = (num, in_min, in_max, out_min, out_max) => { + return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } -var I18n = function (_EventEmitter) { - _inherits__default['default'](I18n, _EventEmitter); - - var _super = _createSuper$3(I18n); - - function I18n() { - var _this; +module.exports = { + init: () => { - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var callback = arguments.length > 1 ? arguments[1] : undefined; + Array.prototype.fast = function(speed = 1) { + this._speed = speed + return this + } - _classCallCheck__default['default'](this, I18n); + Array.prototype.smooth = function(smooth = 1) { + this._smooth = smooth + return this + } - _this = _super.call(this); + Array.prototype.ease = function(ease = 'linear') { + if (typeof ease == 'function') { + this._smooth = 1 + this._ease = ease + } + else if (easing[ease]){ + this._smooth = 1 + this._ease = easing[ease] + } + return this + } - if (isIE10) { - EventEmitter.call(_assertThisInitialized__default['default'](_this)); + Array.prototype.offset = function(offset = 0.5) { + this._offset = offset%1.0 + return this } - _this.options = transformOptions(options); - _this.services = {}; - _this.logger = baseLogger; - _this.modules = { - external: [] - }; - bindMemberFunctions(_assertThisInitialized__default['default'](_this)); + // Array.prototype.bounce = function() { + // this.modifiers.bounce = true + // return this + // } - if (callback && !_this.isInitialized && !options.isClone) { - if (!_this.options.initImmediate) { - _this.init(options, callback); + Array.prototype.fit = function(low = 0, high =1) { + let lowest = Math.min(...this) + let highest = Math.max(...this) + var newArr = this.map((num) => map(num, lowest, highest, low, high)) + newArr._speed = this._speed + newArr._smooth = this._smooth + newArr._ease = this._ease + return newArr + } + }, - return _possibleConstructorReturn__default['default'](_this, _assertThisInitialized__default['default'](_this)); - } + getValue: (arr = []) => ({time, bpm}) =>{ + let speed = arr._speed ? arr._speed : 1 + let smooth = arr._smooth ? arr._smooth : 0 + let index = time * speed * (bpm / 60) + (arr._offset || 0) - setTimeout(function () { - _this.init(options, callback); - }, 0); + if (smooth!==0) { + let ease = arr._ease ? arr._ease : easing['linear'] + let _index = index - (smooth / 2) + let currValue = arr[Math.floor(_index % (arr.length))] + let nextValue = arr[Math.floor((_index + 1) % (arr.length))] + let t = Math.min((_index%1)/smooth,1) + return ease(t) * (nextValue - currValue) + currValue + } + else { + return arr[Math.floor(index % (arr.length))] } - - return _this; } +} - _createClass__default['default'](I18n, [{ - key: "init", - value: function init() { - var _this2 = this; - - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var callback = arguments.length > 1 ? arguments[1] : undefined; +},{"./easing-functions.js":78}],77:[function(require,module,exports){ +const Meyda = require('meyda') - if (typeof options === 'function') { - callback = options; - options = {}; - } +class Audio { + constructor ({ + numBins = 4, + cutoff = 2, + smooth = 0.4, + max = 15, + scale = 10, + isDrawing = false + }) { + this.vol = 0 + this.scale = scale + this.max = max + this.cutoff = cutoff + this.smooth = smooth + this.setBins(numBins) - if (!options.defaultNS && options.ns) { - if (typeof options.ns === 'string') { - options.defaultNS = options.ns; - } else if (options.ns.indexOf('translation') < 0) { - options.defaultNS = options.ns[0]; - } - } + // beat detection from: https://github.com/therewasaguy/p5-music-viz/blob/gh-pages/demos/01d_beat_detect_amplitude/sketch.js + this.beat = { + holdFrames: 20, + threshold: 40, + _cutoff: 0, // adaptive based on sound state + decay: 0.98, + _framesSinceBeat: 0 // keeps track of frames + } - var defOpts = get(); - this.options = _objectSpread$6(_objectSpread$6(_objectSpread$6({}, defOpts), this.options), transformOptions(options)); + this.onBeat = () => { + // console.log("beat") + } - if (this.options.compatibilityAPI !== 'v1') { - this.options.interpolation = _objectSpread$6(_objectSpread$6({}, defOpts.interpolation), this.options.interpolation); - } + this.canvas = document.createElement('canvas') + this.canvas.width = 100 + this.canvas.height = 80 + this.canvas.style.width = "100px" + this.canvas.style.height = "80px" + this.canvas.style.position = 'absolute' + this.canvas.style.right = '0px' + this.canvas.style.bottom = '0px' + document.body.appendChild(this.canvas) - if (options.keySeparator !== undefined) { - this.options.userDefinedKeySeparator = options.keySeparator; - } + this.isDrawing = isDrawing + this.ctx = this.canvas.getContext('2d') + this.ctx.fillStyle="#DFFFFF" + this.ctx.strokeStyle="#0ff" + this.ctx.lineWidth=0.5 + if(window.navigator.mediaDevices) { + window.navigator.mediaDevices.getUserMedia({video: false, audio: true}) + .then((stream) => { + // console.log('got mic stream', stream) + this.stream = stream + this.context = new AudioContext() + // this.context = new AudioContext() + let audio_stream = this.context.createMediaStreamSource(stream) - if (options.nsSeparator !== undefined) { - this.options.userDefinedNsSeparator = options.nsSeparator; - } + // console.log(this.context) + this.meyda = Meyda.createMeydaAnalyzer({ + audioContext: this.context, + source: audio_stream, + featureExtractors: [ + 'loudness', + // 'perceptualSpread', + // 'perceptualSharpness', + // 'spectralCentroid' + ] + }) + }) + .catch((err) => console.log('ERROR', err)) + } + } - function createClassOnDemand(ClassOrObject) { - if (!ClassOrObject) return null; - if (typeof ClassOrObject === 'function') return new ClassOrObject(); - return ClassOrObject; + detectBeat (level) { + //console.log(level, this.beat._cutoff) + if (level > this.beat._cutoff && level > this.beat.threshold) { + this.onBeat() + this.beat._cutoff = level *1.2 + this.beat._framesSinceBeat = 0 + } else { + if (this.beat._framesSinceBeat <= this.beat.holdFrames){ + this.beat._framesSinceBeat ++; + } else { + this.beat._cutoff *= this.beat.decay + this.beat._cutoff = Math.max( this.beat._cutoff, this.beat.threshold); } + } + } - if (!this.options.isClone) { - if (this.modules.logger) { - baseLogger.init(createClassOnDemand(this.modules.logger), this.options); - } else { - baseLogger.init(null, this.options); - } - - var formatter; - - if (this.modules.formatter) { - formatter = this.modules.formatter; - } else if (typeof Intl !== 'undefined') { - formatter = Formatter; - } + tick() { + if(this.meyda){ + var features = this.meyda.get() + if(features && features !== null){ + this.vol = features.loudness.total + this.detectBeat(this.vol) + // reduce loudness array to number of bins + const reducer = (accumulator, currentValue) => accumulator + currentValue; + let spacing = Math.floor(features.loudness.specific.length/this.bins.length) + this.prevBins = this.bins.slice(0) + this.bins = this.bins.map((bin, index) => { + return features.loudness.specific.slice(index * spacing, (index + 1)*spacing).reduce(reducer) + }).map((bin, index) => { + // map to specified range - var lu = new LanguageUtil(this.options); - this.store = new ResourceStore(this.options.resources, this.options); - var s = this.services; - s.logger = baseLogger; - s.resourceStore = this.store; - s.languageUtils = lu; - s.pluralResolver = new PluralResolver(lu, { - prepend: this.options.pluralSeparator, - compatibilityJSON: this.options.compatibilityJSON, - simplifyPluralSuffix: this.options.simplifyPluralSuffix - }); + // return (bin * (1.0 - this.smooth) + this.prevBins[index] * this.smooth) + return (bin * (1.0 - this.settings[index].smooth) + this.prevBins[index] * this.settings[index].smooth) + }) + // var y = this.canvas.height - scale*this.settings[index].cutoff + // this.ctx.beginPath() + // this.ctx.moveTo(index*spacing, y) + // this.ctx.lineTo((index+1)*spacing, y) + // this.ctx.stroke() + // + // var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) + this.fft = this.bins.map((bin, index) => ( + // Math.max(0, (bin - this.cutoff) / (this.max - this.cutoff)) + Math.max(0, (bin - this.settings[index].cutoff)/this.settings[index].scale) + )) + if(this.isDrawing) this.draw() + } + } + } - if (formatter && (!this.options.interpolation.format || this.options.interpolation.format === defOpts.interpolation.format)) { - s.formatter = createClassOnDemand(formatter); - s.formatter.init(s, this.options); - this.options.interpolation.format = s.formatter.format.bind(s.formatter); - } + setCutoff (cutoff) { + this.cutoff = cutoff + this.settings = this.settings.map((el) => { + el.cutoff = cutoff + return el + }) + } - s.interpolator = new Interpolator(this.options); - s.utils = { - hasLoadedNamespace: this.hasLoadedNamespace.bind(this) - }; - s.backendConnector = new Connector(createClassOnDemand(this.modules.backend), s.resourceStore, s, this.options); - s.backendConnector.on('*', function (event) { - for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } + setSmooth (smooth) { + this.smooth = smooth + this.settings = this.settings.map((el) => { + el.smooth = smooth + return el + }) + } - _this2.emit.apply(_this2, [event].concat(args)); - }); + setBins (numBins) { + this.bins = Array(numBins).fill(0) + this.prevBins = Array(numBins).fill(0) + this.fft = Array(numBins).fill(0) + this.settings = Array(numBins).fill(0).map(() => ({ + cutoff: this.cutoff, + scale: this.scale, + smooth: this.smooth + })) + // to do: what to do in non-global mode? + this.bins.forEach((bin, index) => { + window['a' + index] = (scale = 1, offset = 0) => () => (a.fft[index] * scale + offset) + }) + // console.log(this.settings) + } - if (this.modules.languageDetector) { - s.languageDetector = createClassOnDemand(this.modules.languageDetector); - s.languageDetector.init(s, this.options.detection, this.options); - } + setScale(scale){ + this.scale = scale + this.settings = this.settings.map((el) => { + el.scale = scale + return el + }) + } - if (this.modules.i18nFormat) { - s.i18nFormat = createClassOnDemand(this.modules.i18nFormat); - if (s.i18nFormat.init) s.i18nFormat.init(this); - } + setMax(max) { + this.max = max + console.log('set max is deprecated') + } + hide() { + this.isDrawing = false + this.canvas.style.display = 'none' + } - this.translator = new Translator(this.services, this.options); - this.translator.on('*', function (event) { - for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { - args[_key2 - 1] = arguments[_key2]; - } + show() { + this.isDrawing = true + this.canvas.style.display = 'block' - _this2.emit.apply(_this2, [event].concat(args)); - }); - this.modules.external.forEach(function (m) { - if (m.init) m.init(_this2); - }); - } + } - this.format = this.options.interpolation.format; - if (!callback) callback = noop; + draw () { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + var spacing = this.canvas.width / this.bins.length + var scale = this.canvas.height / (this.max * 2) + // console.log(this.bins) + this.bins.forEach((bin, index) => { - if (this.options.fallbackLng && !this.services.languageDetector && !this.options.lng) { - var codes = this.services.languageUtils.getFallbackCodes(this.options.fallbackLng); - if (codes.length > 0 && codes[0] !== 'dev') this.options.lng = codes[0]; - } + var height = bin * scale - if (!this.services.languageDetector && !this.options.lng) { - this.logger.warn('init: no languageDetector is used and no lng is defined'); - } + this.ctx.fillRect(index * spacing, this.canvas.height - height, spacing, height) - var storeApi = ['getResource', 'hasResourceBundle', 'getResourceBundle', 'getDataByLanguage']; - storeApi.forEach(function (fcName) { - _this2[fcName] = function () { - var _this2$store; + // console.log(this.settings[index]) + var y = this.canvas.height - scale*this.settings[index].cutoff + this.ctx.beginPath() + this.ctx.moveTo(index*spacing, y) + this.ctx.lineTo((index+1)*spacing, y) + this.ctx.stroke() - return (_this2$store = _this2.store)[fcName].apply(_this2$store, arguments); - }; - }); - var storeApiChained = ['addResource', 'addResources', 'addResourceBundle', 'removeResourceBundle']; - storeApiChained.forEach(function (fcName) { - _this2[fcName] = function () { - var _this2$store2; + var yMax = this.canvas.height - scale*(this.settings[index].scale + this.settings[index].cutoff) + this.ctx.beginPath() + this.ctx.moveTo(index*spacing, yMax) + this.ctx.lineTo((index+1)*spacing, yMax) + this.ctx.stroke() + }) - (_this2$store2 = _this2.store)[fcName].apply(_this2$store2, arguments); - return _this2; - }; - }); - var deferred = defer(); + /*var y = this.canvas.height - scale*this.cutoff + this.ctx.beginPath() + this.ctx.moveTo(0, y) + this.ctx.lineTo(this.canvas.width, y) + this.ctx.stroke() + var yMax = this.canvas.height - scale*this.max + this.ctx.beginPath() + this.ctx.moveTo(0, yMax) + this.ctx.lineTo(this.canvas.width, yMax) + this.ctx.stroke()*/ + } +} - var load = function load() { - var finish = function finish(err, t) { - if (_this2.isInitialized && !_this2.initializedStoreOnce) _this2.logger.warn('init: i18next is already initialized. You should call init just once!'); - _this2.isInitialized = true; - if (!_this2.options.isClone) _this2.logger.log('initialized', _this2.options); +module.exports = Audio - _this2.emit('initialized', _this2.options); +},{"meyda":92}],78:[function(require,module,exports){ +// from https://gist.github.com/gre/1650294 - deferred.resolve(t); - callback(err, t); - }; +module.exports = { + // no easing, no acceleration + linear: function (t) { return t }, + // accelerating from zero velocity + easeInQuad: function (t) { return t*t }, + // decelerating to zero velocity + easeOutQuad: function (t) { return t*(2-t) }, + // acceleration until halfway, then deceleration + easeInOutQuad: function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t }, + // accelerating from zero velocity + easeInCubic: function (t) { return t*t*t }, + // decelerating to zero velocity + easeOutCubic: function (t) { return (--t)*t*t+1 }, + // acceleration until halfway, then deceleration + easeInOutCubic: function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }, + // accelerating from zero velocity + easeInQuart: function (t) { return t*t*t*t }, + // decelerating to zero velocity + easeOutQuart: function (t) { return 1-(--t)*t*t*t }, + // acceleration until halfway, then deceleration + easeInOutQuart: function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t }, + // accelerating from zero velocity + easeInQuint: function (t) { return t*t*t*t*t }, + // decelerating to zero velocity + easeOutQuint: function (t) { return 1+(--t)*t*t*t*t }, + // acceleration until halfway, then deceleration + easeInOutQuint: function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t }, + // sin shape + sin: function (t) { return (1 + Math.sin(Math.PI*t-Math.PI/2))/2 } +} - if (_this2.languages && _this2.options.compatibilityAPI !== 'v1' && !_this2.isInitialized) return finish(null, _this2.t.bind(_this2)); +},{}],79:[function(require,module,exports){ +// https://github.com/mikolalysenko/mouse-event - _this2.changeLanguage(_this2.options.lng, finish); - }; +'use strict' - if (this.options.resources || !this.options.initImmediate) { - load(); - } else { - setTimeout(load, 0); +function mouseButtons(ev) { + if(typeof ev === 'object') { + if('buttons' in ev) { + return ev.buttons + } else if('which' in ev) { + var b = ev.which + if(b === 2) { + return 4 + } else if(b === 3) { + return 2 + } else if(b > 0) { + return 1<<(b-1) } + } else if('button' in ev) { + var b = ev.button + if(b === 1) { + return 4 + } else if(b === 2) { + return 2 + } else if(b >= 0) { + return 1< 1 && arguments[1] !== undefined ? arguments[1] : noop; - var usedCallback = callback; - var usedLng = typeof language === 'string' ? language : this.language; - if (typeof language === 'function') usedCallback = language; +function mouseRelativeY(ev) { + if(typeof ev === 'object') { + if('pageY' in ev) { + return ev.pageY + } + } + return 0 +} +exports.y = mouseRelativeY - if (!this.options.resources || this.options.partialBundledLanguages) { - if (usedLng && usedLng.toLowerCase() === 'cimode') return usedCallback(); - var toLoad = []; +},{}],80:[function(require,module,exports){ +// based on https://github.com/mikolalysenko/mouse-change - var append = function append(lng) { - if (!lng) return; +'use strict' - var lngs = _this3.services.languageUtils.toResolveHierarchy(lng); +module.exports = mouseListen - lngs.forEach(function (l) { - if (toLoad.indexOf(l) < 0) toLoad.push(l); - }); - }; +var mouse = require('./mouse-event.js') - if (!usedLng) { - var fallbacks = this.services.languageUtils.getFallbackCodes(this.options.fallbackLng); - fallbacks.forEach(function (l) { - return append(l); - }); - } else { - append(usedLng); - } +function mouseListen (element, callback) { + if (!callback) { + callback = element + element = window + } - if (this.options.preload) { - this.options.preload.forEach(function (l) { - return append(l); - }); - } + var buttonState = 0 + var x = 0 + var y = 0 + var mods = { + shift: false, + alt: false, + control: false, + meta: false + } + var attached = false - this.services.backendConnector.load(toLoad, this.options.ns, usedCallback); - } else { - usedCallback(null); - } + function updateMods (ev) { + var changed = false + if ('altKey' in ev) { + changed = changed || ev.altKey !== mods.alt + mods.alt = !!ev.altKey } - }, { - key: "reloadResources", - value: function reloadResources(lngs, ns, callback) { - var deferred = defer(); - if (!lngs) lngs = this.languages; - if (!ns) ns = this.options.ns; - if (!callback) callback = noop; - this.services.backendConnector.reload(lngs, ns, function (err) { - deferred.resolve(); - callback(err); - }); - return deferred; + if ('shiftKey' in ev) { + changed = changed || ev.shiftKey !== mods.shift + mods.shift = !!ev.shiftKey } - }, { - key: "use", - value: function use(module) { - if (!module) throw new Error('You are passing an undefined module! Please check the object you are passing to i18next.use()'); - if (!module.type) throw new Error('You are passing a wrong module! Please check the object you are passing to i18next.use()'); + if ('ctrlKey' in ev) { + changed = changed || ev.ctrlKey !== mods.control + mods.control = !!ev.ctrlKey + } + if ('metaKey' in ev) { + changed = changed || ev.metaKey !== mods.meta + mods.meta = !!ev.metaKey + } + return changed + } - if (module.type === 'backend') { - this.modules.backend = module; - } + function handleEvent (nextButtons, ev) { + var nextX = mouse.x(ev) + var nextY = mouse.y(ev) + if ('buttons' in ev) { + nextButtons = ev.buttons | 0 + } + if (nextButtons !== buttonState || + nextX !== x || + nextY !== y || + updateMods(ev)) { + buttonState = nextButtons | 0 + x = nextX || 0 + y = nextY || 0 + callback && callback(buttonState, x, y, mods) + } + } - if (module.type === 'logger' || module.log && module.warn && module.error) { - this.modules.logger = module; - } + function clearState (ev) { + handleEvent(0, ev) + } - if (module.type === 'languageDetector') { - this.modules.languageDetector = module; - } + function handleBlur () { + if (buttonState || + x || + y || + mods.shift || + mods.alt || + mods.meta || + mods.control) { + x = y = 0 + buttonState = 0 + mods.shift = mods.alt = mods.control = mods.meta = false + callback && callback(0, 0, 0, mods) + } + } - if (module.type === 'i18nFormat') { - this.modules.i18nFormat = module; - } + function handleMods (ev) { + if (updateMods(ev)) { + callback && callback(buttonState, x, y, mods) + } + } - if (module.type === 'postProcessor') { - postProcessor.addPostProcessor(module); - } + function handleMouseMove (ev) { + if (mouse.buttons(ev) === 0) { + handleEvent(0, ev) + } else { + handleEvent(buttonState, ev) + } + } - if (module.type === 'formatter') { - this.modules.formatter = module; - } + function handleMouseDown (ev) { + handleEvent(buttonState | mouse.buttons(ev), ev) + } - if (module.type === '3rdParty') { - this.modules.external.push(module); - } + function handleMouseUp (ev) { + handleEvent(buttonState & ~mouse.buttons(ev), ev) + } - return this; + function attachListeners () { + if (attached) { + return } - }, { - key: "changeLanguage", - value: function changeLanguage(lng, callback) { - var _this4 = this; + attached = true - this.isLanguageChangingTo = lng; - var deferred = defer(); - this.emit('languageChanging', lng); + element.addEventListener('mousemove', handleMouseMove) - var setLngProps = function setLngProps(l) { - _this4.language = l; - _this4.languages = _this4.services.languageUtils.toResolveHierarchy(l); - _this4.resolvedLanguage = undefined; - if (['cimode', 'dev'].indexOf(l) > -1) return; + element.addEventListener('mousedown', handleMouseDown) - for (var li = 0; li < _this4.languages.length; li++) { - var lngInLngs = _this4.languages[li]; - if (['cimode', 'dev'].indexOf(lngInLngs) > -1) continue; + element.addEventListener('mouseup', handleMouseUp) - if (_this4.store.hasLanguageSomeTranslations(lngInLngs)) { - _this4.resolvedLanguage = lngInLngs; - break; - } - } - }; + element.addEventListener('mouseleave', clearState) + element.addEventListener('mouseenter', clearState) + element.addEventListener('mouseout', clearState) + element.addEventListener('mouseover', clearState) - var done = function done(err, l) { - if (l) { - setLngProps(l); + element.addEventListener('blur', handleBlur) - _this4.translator.changeLanguage(l); + element.addEventListener('keyup', handleMods) + element.addEventListener('keydown', handleMods) + element.addEventListener('keypress', handleMods) - _this4.isLanguageChangingTo = undefined; + if (element !== window) { + window.addEventListener('blur', handleBlur) - _this4.emit('languageChanged', l); + window.addEventListener('keyup', handleMods) + window.addEventListener('keydown', handleMods) + window.addEventListener('keypress', handleMods) + } + } - _this4.logger.log('languageChanged', l); - } else { - _this4.isLanguageChangingTo = undefined; - } + function detachListeners () { + if (!attached) { + return + } + attached = false - deferred.resolve(function () { - return _this4.t.apply(_this4, arguments); - }); - if (callback) callback(err, function () { - return _this4.t.apply(_this4, arguments); - }); - }; + element.removeEventListener('mousemove', handleMouseMove) - var setLng = function setLng(lngs) { - if (!lng && !lngs && _this4.services.languageDetector) lngs = []; - var l = typeof lngs === 'string' ? lngs : _this4.services.languageUtils.getBestMatchFromCodes(lngs); + element.removeEventListener('mousedown', handleMouseDown) - if (l) { - if (!_this4.language) { - setLngProps(l); - } + element.removeEventListener('mouseup', handleMouseUp) - if (!_this4.translator.language) _this4.translator.changeLanguage(l); - if (_this4.services.languageDetector) _this4.services.languageDetector.cacheUserLanguage(l); - } + element.removeEventListener('mouseleave', clearState) + element.removeEventListener('mouseenter', clearState) + element.removeEventListener('mouseout', clearState) + element.removeEventListener('mouseover', clearState) - _this4.loadResources(l, function (err) { - done(err, l); - }); - }; + element.removeEventListener('blur', handleBlur) - if (!lng && this.services.languageDetector && !this.services.languageDetector.async) { - setLng(this.services.languageDetector.detect()); - } else if (!lng && this.services.languageDetector && this.services.languageDetector.async) { - this.services.languageDetector.detect(setLng); - } else { - setLng(lng); - } + element.removeEventListener('keyup', handleMods) + element.removeEventListener('keydown', handleMods) + element.removeEventListener('keypress', handleMods) - return deferred; + if (element !== window) { + window.removeEventListener('blur', handleBlur) + + window.removeEventListener('keyup', handleMods) + window.removeEventListener('keydown', handleMods) + window.removeEventListener('keypress', handleMods) } - }, { - key: "getFixedT", - value: function getFixedT(lng, ns, keyPrefix) { - var _this5 = this; + } - var fixedT = function fixedT(key, opts) { - var options; + // Attach listeners + attachListeners() - if (_typeof__default['default'](opts) !== 'object') { - for (var _len3 = arguments.length, rest = new Array(_len3 > 2 ? _len3 - 2 : 0), _key3 = 2; _key3 < _len3; _key3++) { - rest[_key3 - 2] = arguments[_key3]; - } + var result = { + element: element + } - options = _this5.options.overloadTranslationOptionHandler([key, opts].concat(rest)); + Object.defineProperties(result, { + enabled: { + get: function () { return attached }, + set: function (f) { + if (f) { + attachListeners() } else { - options = _objectSpread$6({}, opts); + detachListeners() } + }, + enumerable: true + }, + buttons: { + get: function () { return buttonState }, + enumerable: true + }, + x: { + get: function () { return x }, + enumerable: true + }, + y: { + get: function () { return y }, + enumerable: true + }, + mods: { + get: function () { return mods }, + enumerable: true + } + }) - options.lng = options.lng || fixedT.lng; - options.lngs = options.lngs || fixedT.lngs; - options.ns = options.ns || fixedT.ns; - var keySeparator = _this5.options.keySeparator || '.'; - var resultKey = keyPrefix ? "".concat(keyPrefix).concat(keySeparator).concat(key) : key; - return _this5.t(resultKey, options); - }; + return result +} - if (typeof lng === 'string') { - fixedT.lng = lng; - } else { - fixedT.lngs = lng; - } +},{"./mouse-event.js":79}],81:[function(require,module,exports){ +// attempt custom evaluation sandbox for hydra functions +// for now, just avoids polluting the global namespace +// should probably be replaced with an abstract syntax tree - fixedT.ns = ns; - fixedT.keyPrefix = keyPrefix; - return fixedT; - } - }, { - key: "t", - value: function t() { - var _this$translator; +module.exports = (parent) => { + var initialCode = `` - return this.translator && (_this$translator = this.translator).translate.apply(_this$translator, arguments); - } - }, { - key: "exists", - value: function exists() { - var _this$translator2; + var sandbox = createSandbox(initialCode) - return this.translator && (_this$translator2 = this.translator).exists.apply(_this$translator2, arguments); - } - }, { - key: "setDefaultNamespace", - value: function setDefaultNamespace(ns) { - this.options.defaultNS = ns; + var addToContext = (name, object) => { + initialCode += ` + var ${name} = ${object} + ` + sandbox = createSandbox(initialCode) + } + + + return { + addToContext: addToContext, + eval: (code) => sandbox.eval(code) + } + + function createSandbox (initial) { + eval(initial) + // optional params + var localEval = function (code) { + eval(code) } - }, { - key: "hasLoadedNamespace", - value: function hasLoadedNamespace(ns) { - var _this6 = this; - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + // API/data for end-user + return { + eval: localEval + } + } +} - if (!this.isInitialized) { - this.logger.warn('hasLoadedNamespace: i18next was not initialized', this.languages); - return false; - } +},{}],82:[function(require,module,exports){ - if (!this.languages || !this.languages.length) { - this.logger.warn('hasLoadedNamespace: i18n.languages were undefined or empty', this.languages); - return false; - } +module.exports = function (options) { + return new Promise(function(resolve, reject) { + // async function startCapture(displayMediaOptions) { + navigator.mediaDevices.getDisplayMedia(options).then((stream) => { + const video = document.createElement('video') + video.srcObject = stream + video.addEventListener('loadedmetadata', () => { + video.play() + resolve({video: video}) + }) + }).catch((err) => reject(err)) + }) +} - var lng = this.resolvedLanguage || this.languages[0]; - var fallbackLng = this.options ? this.options.fallbackLng : false; - var lastLng = this.languages[this.languages.length - 1]; - if (lng.toLowerCase() === 'cimode') return true; +},{}],83:[function(require,module,exports){ +class VideoRecorder { + constructor(stream) { + this.mediaSource = new MediaSource() + this.stream = stream - var loadNotPending = function loadNotPending(l, n) { - var loadState = _this6.services.backendConnector.state["".concat(l, "|").concat(n)]; + // testing using a recording as input + this.output = document.createElement('video') + this.output.autoplay = true + this.output.loop = true - return loadState === -1 || loadState === 2; - }; + let self = this + this.mediaSource.addEventListener('sourceopen', () => { + console.log('MediaSource opened'); + self.sourceBuffer = self.mediaSource.addSourceBuffer('video/webm; codecs="vp8"'); + console.log('Source buffer: ', sourceBuffer); + }) + } - if (options.precheck) { - var preResult = options.precheck(this, loadNotPending); - if (preResult !== undefined) return preResult; - } + start() { + // let options = {mimeType: 'video/webm'}; - if (this.hasResourceBundle(lng, ns)) return true; - if (!this.services.backendConnector.backend) return true; - if (loadNotPending(lng, ns) && (!fallbackLng || loadNotPending(lastLng, ns))) return true; - return false; - } - }, { - key: "loadNamespaces", - value: function loadNamespaces(ns, callback) { - var _this7 = this; +// let options = {mimeType: 'video/webm;codecs=h264'}; + let options = {mimeType: 'video/webm;codecs=vp9'}; - var deferred = defer(); + this.recordedBlobs = [] + try { + this.mediaRecorder = new MediaRecorder(this.stream, options) + } catch (e0) { + console.log('Unable to create MediaRecorder with options Object: ', e0) + try { + options = {mimeType: 'video/webm,codecs=vp9'} + this.mediaRecorder = new MediaRecorder(this.stream, options) + } catch (e1) { + console.log('Unable to create MediaRecorder with options Object: ', e1) + try { + options = 'video/vp8' // Chrome 47 + this.mediaRecorder = new MediaRecorder(this.stream, options) + } catch (e2) { + alert('MediaRecorder is not supported by this browser.\n\n' + + 'Try Firefox 29 or later, or Chrome 47 or later, ' + + 'with Enable experimental Web Platform features enabled from chrome://flags.') + console.error('Exception while creating MediaRecorder:', e2) + return + } + } + } + console.log('Created MediaRecorder', this.mediaRecorder, 'with options', options); + this.mediaRecorder.onstop = this._handleStop.bind(this) + this.mediaRecorder.ondataavailable = this._handleDataAvailable.bind(this) + this.mediaRecorder.start(100) // collect 100ms of data + console.log('MediaRecorder started', this.mediaRecorder) + } - if (!this.options.ns) { - callback && callback(); - return Promise.resolve(); - } + + stop(){ + this.mediaRecorder.stop() + } - if (typeof ns === 'string') ns = [ns]; - ns.forEach(function (n) { - if (_this7.options.ns.indexOf(n) < 0) _this7.options.ns.push(n); - }); - this.loadResources(function (err) { - deferred.resolve(); - if (callback) callback(err); - }); - return deferred; - } - }, { - key: "loadLanguages", - value: function loadLanguages(lngs, callback) { - var deferred = defer(); - if (typeof lngs === 'string') lngs = [lngs]; - var preloaded = this.options.preload || []; - var newLngs = lngs.filter(function (lng) { - return preloaded.indexOf(lng) < 0; - }); + _handleStop() { + //const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'}) + // const blob = new Blob(this.recordedBlobs, {type: 'video/webm;codecs=h264'}) + const blob = new Blob(this.recordedBlobs, {type: this.mediaRecorder.mimeType}) + const url = window.URL.createObjectURL(blob) + this.output.src = url - if (!newLngs.length) { - if (callback) callback(); - return Promise.resolve(); - } + const a = document.createElement('a') + a.style.display = 'none' + a.href = url + let d = new Date() + a.download = `hydra-${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}-${d.getHours()}.${d.getMinutes()}.${d.getSeconds()}.webm` + document.body.appendChild(a) + a.click() + setTimeout(() => { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 300); + } - this.options.preload = preloaded.concat(newLngs); - this.loadResources(function (err) { - deferred.resolve(); - if (callback) callback(err); - }); - return deferred; - } - }, { - key: "dir", - value: function dir(lng) { - if (!lng) lng = this.resolvedLanguage || (this.languages && this.languages.length > 0 ? this.languages[0] : this.language); - if (!lng) return 'rtl'; - var rtlLngs = ['ar', 'shu', 'sqr', 'ssh', 'xaa', 'yhd', 'yud', 'aao', 'abh', 'abv', 'acm', 'acq', 'acw', 'acx', 'acy', 'adf', 'ads', 'aeb', 'aec', 'afb', 'ajp', 'apc', 'apd', 'arb', 'arq', 'ars', 'ary', 'arz', 'auz', 'avl', 'ayh', 'ayl', 'ayn', 'ayp', 'bbz', 'pga', 'he', 'iw', 'ps', 'pbt', 'pbu', 'pst', 'prp', 'prd', 'ug', 'ur', 'ydd', 'yds', 'yih', 'ji', 'yi', 'hbo', 'men', 'xmn', 'fa', 'jpr', 'peo', 'pes', 'prs', 'dv', 'sam', 'ckb']; - return rtlLngs.indexOf(this.services.languageUtils.getLanguagePartFromCode(lng)) > -1 || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr'; + _handleDataAvailable(event) { + if (event.data && event.data.size > 0) { + this.recordedBlobs.push(event.data); } - }, { - key: "cloneInstance", - value: function cloneInstance() { - var _this8 = this; + } +} - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop; +module.exports = VideoRecorder - var mergedOptions = _objectSpread$6(_objectSpread$6(_objectSpread$6({}, this.options), options), { - isClone: true - }); +},{}],84:[function(require,module,exports){ +//const enumerateDevices = require('enumerate-devices') - var clone = new I18n(mergedOptions); - var membersToCopy = ['store', 'services', 'language']; - membersToCopy.forEach(function (m) { - clone[m] = _this8[m]; - }); - clone.services = _objectSpread$6({}, this.services); - clone.services.utils = { - hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone) - }; - clone.translator = new Translator(clone.services, clone.options); - clone.translator.on('*', function (event) { - for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { - args[_key4 - 1] = arguments[_key4]; +module.exports = function (deviceId) { + return navigator.mediaDevices.enumerateDevices() + .then(devices => devices.filter(devices => devices.kind === 'videoinput')) + .then(cameras => { + let constraints = { audio: false, video: true} + if (cameras[deviceId]) { + constraints['video'] = { + deviceId: { exact: cameras[deviceId].deviceId } } + } + // console.log(cameras) + return window.navigator.mediaDevices.getUserMedia(constraints) + }) + .then(stream => { + const video = document.createElement('video') + video.setAttribute('autoplay', '') + video.setAttribute('muted', '') + video.setAttribute('playsinline', '') + // video.src = window.URL.createObjectURL(stream) + video.srcObject = stream + return new Promise((resolve, reject) => { + video.addEventListener('loadedmetadata', () => { + video.play().then(() => resolve({video: video})) + }) + }) + }) + .catch(console.log.bind(console)) +} - clone.emit.apply(clone, [event].concat(args)); - }); - clone.init(mergedOptions, callback); - clone.translator.options = clone.options; - clone.translator.backendConnector.services.utils = { - hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone) - }; - return clone; - } - }, { - key: "toJSON", - value: function toJSON() { - return { - options: this.options, - store: this.store, - language: this.language, - languages: this.languages, - resolvedLanguage: this.resolvedLanguage - }; - } - }]); +},{}],85:[function(require,module,exports){ +//const transforms = require('./glsl-transforms.js') - return I18n; -}(EventEmitter); +var Output = function ({ regl, precision, label = "", width, height}) { + this.regl = regl + this.precision = precision + this.label = label + this.positionBuffer = this.regl.buffer([ + [-2, 0], + [0, -2], + [2, 2] + ]) -_defineProperty__default['default'](I18n, "createInstance", function () { - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var callback = arguments.length > 1 ? arguments[1] : undefined; - return new I18n(options, callback); -}); + this.draw = () => {} + this.init() + this.pingPongIndex = 0 -var instance = I18n.createInstance(); -instance.createInstance = I18n.createInstance; + // for each output, create two fbos for pingponging + this.fbos = (Array(2)).fill().map(() => this.regl.framebuffer({ + color: this.regl.texture({ + mag: 'nearest', + width: width, + height: height, + format: 'rgba' + }), + depthStencil: false + })) -module.exports = instance; + // array containing render passes +// this.passes = [] +} -},{"@babel/runtime/helpers/assertThisInitialized":31,"@babel/runtime/helpers/classCallCheck":32,"@babel/runtime/helpers/createClass":33,"@babel/runtime/helpers/defineProperty":34,"@babel/runtime/helpers/getPrototypeOf":35,"@babel/runtime/helpers/inherits":36,"@babel/runtime/helpers/possibleConstructorReturn":39,"@babel/runtime/helpers/toArray":41,"@babel/runtime/helpers/typeof":42}],83:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }) - } - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } +Output.prototype.resize = function(width, height) { + this.fbos.forEach((fbo) => { + fbo.resize(width, height) + }) +// console.log(this) } -},{}],84:[function(require,module,exports){ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["Meyda"] = factory(); - else - root["Meyda"] = factory(); -})(window, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); -/******/ }) -/************************************************************************/ -/******/ ({ -/***/ "./node_modules/assert/assert.js": -/*!***************************************!*\ - !*** ./node_modules/assert/assert.js ***! - \***************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { +Output.prototype.getCurrent = function () { + return this.fbos[this.pingPongIndex] +} -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { +Output.prototype.getTexture = function () { + var index = this.pingPongIndex ? 0 : 1 + return this.fbos[index] +} -// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js -// original notice: +Output.prototype.init = function () { +// console.log('clearing') + this.transformIndex = 0 + this.fragHeader = ` + precision ${this.precision} float; -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -function compare(a, b) { - if (a === b) { - return 0; - } + uniform float time; + varying vec2 uv; + ` - var x = a.length; - var y = b.length; + this.fragBody = `` - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i]; - y = b[i]; - break; - } - } + this.vert = ` + precision ${this.precision} float; + attribute vec2 position; + varying vec2 uv; - if (x < y) { - return -1; + void main () { + uv = position; + gl_Position = vec4(2.0 * position - 1.0, 0, 1); + }` + + this.attributes = { + position: this.positionBuffer } - if (y < x) { - return 1; + this.uniforms = { + time: this.regl.prop('time'), + resolution: this.regl.prop('resolution') } - return 0; + + this.frag = ` + ${this.fragHeader} + + void main () { + vec4 c = vec4(0, 0, 0, 0); + vec2 st = uv; + ${this.fragBody} + gl_FragColor = c; + } + ` + return this +} + + +Output.prototype.render = function (passes) { + let pass = passes[0] + //console.log('pass', pass, this.pingPongIndex) + var self = this + var uniforms = Object.assign(pass.uniforms, { prevBuffer: () => { + //var index = this.pingPongIndex ? 0 : 1 + // var index = self.pingPong[(passIndex+1)%2] + // console.log('ping pong', self.pingPongIndex) + return self.fbos[self.pingPongIndex] + } + }) + + self.draw = self.regl({ + frag: pass.frag, + vert: self.vert, + attributes: self.attributes, + uniforms: uniforms, + count: 3, + framebuffer: () => { + self.pingPongIndex = self.pingPongIndex ? 0 : 1 + return self.fbos[self.pingPongIndex] + } + }) } -function isBuffer(b) { - if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { - return global.Buffer.isBuffer(b); - } - return !!(b != null && b._isBuffer); + + +Output.prototype.tick = function (props) { +// console.log(props) + this.draw(props) } -// based on node assert, original notice: +module.exports = Output -// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 -// -// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! -// -// Originally from narwhal.js (http://narwhaljs.org) -// Copyright (c) 2009 Thomas Robinson <280north.com> -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the 'Software'), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +},{}],86:[function(require,module,exports){ +module.exports = attributeToProperty -var util = __webpack_require__(/*! util/ */ "./node_modules/webpack-stream/node_modules/util/util.js"); -var hasOwn = Object.prototype.hasOwnProperty; -var pSlice = Array.prototype.slice; -var functionsHaveNames = (function () { - return function foo() {}.name === 'foo'; -}()); -function pToString (obj) { - return Object.prototype.toString.call(obj); +var transform = { + 'class': 'className', + 'for': 'htmlFor', + 'http-equiv': 'httpEquiv' } -function isView(arrbuf) { - if (isBuffer(arrbuf)) { - return false; - } - if (typeof global.ArrayBuffer !== 'function') { - return false; - } - if (typeof ArrayBuffer.isView === 'function') { - return ArrayBuffer.isView(arrbuf); - } - if (!arrbuf) { - return false; - } - if (arrbuf instanceof DataView) { - return true; - } - if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { - return true; + +function attributeToProperty (h) { + return function (tagName, attrs, children) { + for (var attr in attrs) { + if (attr in transform) { + attrs[transform[attr]] = attrs[attr] + delete attrs[attr] + } + } + return h(tagName, attrs, children) } - return false; } -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. -var assert = module.exports = ok; +},{}],87:[function(require,module,exports){ +var attrToProp = require('hyperscript-attribute-to-property') -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) +var VAR = 0, TEXT = 1, OPEN = 2, CLOSE = 3, ATTR = 4 +var ATTR_KEY = 5, ATTR_KEY_W = 6 +var ATTR_VALUE_W = 7, ATTR_VALUE = 8 +var ATTR_VALUE_SQ = 9, ATTR_VALUE_DQ = 10 +var ATTR_EQ = 11, ATTR_BREAK = 12 +var COMMENT = 13 -var regex = /\s*function\s+([^\(\s]*)\s*/; -// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js -function getName(func) { - if (!util.isFunction(func)) { - return; - } - if (functionsHaveNames) { - return func.name; +module.exports = function (h, opts) { + if (!opts) opts = {} + var concat = opts.concat || function (a, b) { + return String(a) + String(b) } - var str = func.toString(); - var match = str.match(regex); - return match && match[1]; -} -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - if (options.message) { - this.message = options.message; - this.generatedMessage = false; - } else { - this.message = getMessage(this); - this.generatedMessage = true; + if (opts.attrToProp !== false) { + h = attrToProp(h) } - var stackStartFunction = options.stackStartFunction || fail; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } else { - // non v8 browsers so we can have a stacktrace - var err = new Error(); - if (err.stack) { - var out = err.stack; - // try to strip useless frames - var fn_name = getName(stackStartFunction); - var idx = out.indexOf('\n' + fn_name); - if (idx >= 0) { - // once we have located the function frame - // we need to strip out everything before it (and its line) - var next_line = out.indexOf('\n', idx + 1); - out = out.substring(next_line + 1); + return function (strings) { + var state = TEXT, reg = '' + var arglen = arguments.length + var parts = [] + + for (var i = 0; i < strings.length; i++) { + if (i < arglen - 1) { + var arg = arguments[i+1] + var p = parse(strings[i]) + var xstate = state + if (xstate === ATTR_VALUE_DQ) xstate = ATTR_VALUE + if (xstate === ATTR_VALUE_SQ) xstate = ATTR_VALUE + if (xstate === ATTR_VALUE_W) xstate = ATTR_VALUE + if (xstate === ATTR) xstate = ATTR_KEY + if (xstate === OPEN) { + if (reg === '/') { + p.push([ OPEN, '/', arg ]) + reg = '' + } else { + p.push([ OPEN, arg ]) + } + } else if (xstate === COMMENT && opts.comments) { + reg += String(arg) + } else if (xstate !== COMMENT) { + p.push([ VAR, xstate, arg ]) + } + parts.push.apply(parts, p) + } else parts.push.apply(parts, parse(strings[i])) + } + + var tree = [null,{},[]] + var stack = [[tree,-1]] + for (var i = 0; i < parts.length; i++) { + var cur = stack[stack.length-1][0] + var p = parts[i], s = p[0] + if (s === OPEN && /^\//.test(p[1])) { + var ix = stack[stack.length-1][1] + if (stack.length > 1) { + stack.pop() + stack[stack.length-1][0][2][ix] = h( + cur[0], cur[1], cur[2].length ? cur[2] : undefined + ) + } + } else if (s === OPEN) { + var c = [p[1],{},[]] + cur[2].push(c) + stack.push([c,cur[2].length-1]) + } else if (s === ATTR_KEY || (s === VAR && p[1] === ATTR_KEY)) { + var key = '' + var copyKey + for (; i < parts.length; i++) { + if (parts[i][0] === ATTR_KEY) { + key = concat(key, parts[i][1]) + } else if (parts[i][0] === VAR && parts[i][1] === ATTR_KEY) { + if (typeof parts[i][2] === 'object' && !key) { + for (copyKey in parts[i][2]) { + if (parts[i][2].hasOwnProperty(copyKey) && !cur[1][copyKey]) { + cur[1][copyKey] = parts[i][2][copyKey] + } + } + } else { + key = concat(key, parts[i][2]) + } + } else break + } + if (parts[i][0] === ATTR_EQ) i++ + var j = i + for (; i < parts.length; i++) { + if (parts[i][0] === ATTR_VALUE || parts[i][0] === ATTR_KEY) { + if (!cur[1][key]) cur[1][key] = strfn(parts[i][1]) + else parts[i][1]==="" || (cur[1][key] = concat(cur[1][key], parts[i][1])); + } else if (parts[i][0] === VAR + && (parts[i][1] === ATTR_VALUE || parts[i][1] === ATTR_KEY)) { + if (!cur[1][key]) cur[1][key] = strfn(parts[i][2]) + else parts[i][2]==="" || (cur[1][key] = concat(cur[1][key], parts[i][2])); + } else { + if (key.length && !cur[1][key] && i === j + && (parts[i][0] === CLOSE || parts[i][0] === ATTR_BREAK)) { + // https://html.spec.whatwg.org/multipage/infrastructure.html#boolean-attributes + // empty string is falsy, not well behaved value in browser + cur[1][key] = key.toLowerCase() + } + if (parts[i][0] === CLOSE) { + i-- + } + break + } + } + } else if (s === ATTR_KEY) { + cur[1][p[1]] = true + } else if (s === VAR && p[1] === ATTR_KEY) { + cur[1][p[2]] = true + } else if (s === CLOSE) { + if (selfClosing(cur[0]) && stack.length) { + var ix = stack[stack.length-1][1] + stack.pop() + stack[stack.length-1][0][2][ix] = h( + cur[0], cur[1], cur[2].length ? cur[2] : undefined + ) + } + } else if (s === VAR && p[1] === TEXT) { + if (p[2] === undefined || p[2] === null) p[2] = '' + else if (!p[2]) p[2] = concat('', p[2]) + if (Array.isArray(p[2][0])) { + cur[2].push.apply(cur[2], p[2]) + } else { + cur[2].push(p[2]) + } + } else if (s === TEXT) { + cur[2].push(p[1]) + } else if (s === ATTR_EQ || s === ATTR_BREAK) { + // no-op + } else { + throw new Error('unhandled: ' + s) } + } - this.stack = out; + if (tree[2].length > 1 && /^\s*$/.test(tree[2][0])) { + tree[2].shift() } - } -}; -// assert.AssertionError instanceof Error -util.inherits(assert.AssertionError, Error); + if (tree[2].length > 2 + || (tree[2].length === 2 && /\S/.test(tree[2][1]))) { + if (opts.createFragment) return opts.createFragment(tree[2]) + throw new Error( + 'multiple root elements must be wrapped in an enclosing tag' + ) + } + if (Array.isArray(tree[2][0]) && typeof tree[2][0][0] === 'string' + && Array.isArray(tree[2][0][2])) { + tree[2][0] = h(tree[2][0][0], tree[2][0][1], tree[2][0][2]) + } + return tree[2][0] -function truncate(s, n) { - if (typeof s === 'string') { - return s.length < n ? s : s.slice(0, n); - } else { - return s; + function parse (str) { + var res = [] + if (state === ATTR_VALUE_W) state = ATTR + for (var i = 0; i < str.length; i++) { + var c = str.charAt(i) + if (state === TEXT && c === '<') { + if (reg.length) res.push([TEXT, reg]) + reg = '' + state = OPEN + } else if (c === '>' && !quot(state) && state !== COMMENT) { + if (state === OPEN && reg.length) { + res.push([OPEN,reg]) + } else if (state === ATTR_KEY) { + res.push([ATTR_KEY,reg]) + } else if (state === ATTR_VALUE && reg.length) { + res.push([ATTR_VALUE,reg]) + } + res.push([CLOSE]) + reg = '' + state = TEXT + } else if (state === COMMENT && /-$/.test(reg) && c === '-') { + if (opts.comments) { + res.push([ATTR_VALUE,reg.substr(0, reg.length - 1)]) + } + reg = '' + state = TEXT + } else if (state === OPEN && /^!--$/.test(reg)) { + if (opts.comments) { + res.push([OPEN, reg],[ATTR_KEY,'comment'],[ATTR_EQ]) + } + reg = c + state = COMMENT + } else if (state === TEXT || state === COMMENT) { + reg += c + } else if (state === OPEN && c === '/' && reg.length) { + // no-op, self closing tag without a space
+ } else if (state === OPEN && /\s/.test(c)) { + if (reg.length) { + res.push([OPEN, reg]) + } + reg = '' + state = ATTR + } else if (state === OPEN) { + reg += c + } else if (state === ATTR && /[^\s"'=/]/.test(c)) { + state = ATTR_KEY + reg = c + } else if (state === ATTR && /\s/.test(c)) { + if (reg.length) res.push([ATTR_KEY,reg]) + res.push([ATTR_BREAK]) + } else if (state === ATTR_KEY && /\s/.test(c)) { + res.push([ATTR_KEY,reg]) + reg = '' + state = ATTR_KEY_W + } else if (state === ATTR_KEY && c === '=') { + res.push([ATTR_KEY,reg],[ATTR_EQ]) + reg = '' + state = ATTR_VALUE_W + } else if (state === ATTR_KEY) { + reg += c + } else if ((state === ATTR_KEY_W || state === ATTR) && c === '=') { + res.push([ATTR_EQ]) + state = ATTR_VALUE_W + } else if ((state === ATTR_KEY_W || state === ATTR) && !/\s/.test(c)) { + res.push([ATTR_BREAK]) + if (/[\w-]/.test(c)) { + reg += c + state = ATTR_KEY + } else state = ATTR + } else if (state === ATTR_VALUE_W && c === '"') { + state = ATTR_VALUE_DQ + } else if (state === ATTR_VALUE_W && c === "'") { + state = ATTR_VALUE_SQ + } else if (state === ATTR_VALUE_DQ && c === '"') { + res.push([ATTR_VALUE,reg],[ATTR_BREAK]) + reg = '' + state = ATTR + } else if (state === ATTR_VALUE_SQ && c === "'") { + res.push([ATTR_VALUE,reg],[ATTR_BREAK]) + reg = '' + state = ATTR + } else if (state === ATTR_VALUE_W && !/\s/.test(c)) { + state = ATTR_VALUE + i-- + } else if (state === ATTR_VALUE && /\s/.test(c)) { + res.push([ATTR_VALUE,reg],[ATTR_BREAK]) + reg = '' + state = ATTR + } else if (state === ATTR_VALUE || state === ATTR_VALUE_SQ + || state === ATTR_VALUE_DQ) { + reg += c + } + } + if (state === TEXT && reg.length) { + res.push([TEXT,reg]) + reg = '' + } else if (state === ATTR_VALUE && reg.length) { + res.push([ATTR_VALUE,reg]) + reg = '' + } else if (state === ATTR_VALUE_DQ && reg.length) { + res.push([ATTR_VALUE,reg]) + reg = '' + } else if (state === ATTR_VALUE_SQ && reg.length) { + res.push([ATTR_VALUE,reg]) + reg = '' + } else if (state === ATTR_KEY) { + res.push([ATTR_KEY,reg]) + reg = '' + } + return res + } } -} -function inspect(something) { - if (functionsHaveNames || !util.isFunction(something)) { - return util.inspect(something); + + function strfn (x) { + if (typeof x === 'function') return x + else if (typeof x === 'string') return x + else if (x && typeof x === 'object') return x + else if (x === null || x === undefined) return x + else return concat('', x) } - var rawname = getName(something); - var name = rawname ? ': ' + rawname : ''; - return '[Function' + name + ']'; } -function getMessage(self) { - return truncate(inspect(self.actual), 128) + ' ' + - self.operator + ' ' + - truncate(inspect(self.expected), 128); + +function quot (state) { + return state === ATTR_VALUE_SQ || state === ATTR_VALUE_DQ } -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. +var closeRE = RegExp('^(' + [ + 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command', 'embed', + 'frame', 'hr', 'img', 'input', 'isindex', 'keygen', 'link', 'meta', 'param', + 'source', 'track', 'wbr', '!--', + // SVG TAGS + 'animate', 'animateTransform', 'circle', 'cursor', 'desc', 'ellipse', + 'feBlend', 'feColorMatrix', 'feComposite', + 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', + 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', + 'feGaussianBlur', 'feImage', 'feMergeNode', 'feMorphology', + 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', + 'feTurbulence', 'font-face-format', 'font-face-name', 'font-face-uri', + 'glyph', 'glyphRef', 'hkern', 'image', 'line', 'missing-glyph', 'mpath', + 'path', 'polygon', 'polyline', 'rect', 'set', 'stop', 'tref', 'use', 'view', + 'vkern' +].join('|') + ')(?:[\.#][a-zA-Z0-9\u007F-\uFFFF_:-]+)*$') +function selfClosing (tag) { return closeRE.test(tag) } -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. +},{"hyperscript-attribute-to-property":86}],88:[function(require,module,exports){ +'use strict'; -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} +var _classCallCheck = require('@babel/runtime/helpers/classCallCheck'); +var _createClass = require('@babel/runtime/helpers/createClass'); -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; +function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, !!guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. +var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck); +var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass); -function ok(value, message) { - if (!value) fail(value, true, message, '==', assert.ok); +var arr = []; +var each = arr.forEach; +var slice = arr.slice; +function defaults(obj) { + each.call(slice.call(arguments, 1), function (source) { + if (source) { + for (var prop in source) { + if (obj[prop] === undefined) obj[prop] = source[prop]; + } + } + }); + return obj; } -assert.ok = ok; - -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); -}; +// eslint-disable-next-line no-control-regex +var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); +var serializeCookie = function serializeCookie(name, val, options) { + var opt = options || {}; + opt.path = opt.path || '/'; + var value = encodeURIComponent(val); + var str = name + '=' + value; -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); + if (opt.maxAge > 0) { + var maxAge = opt.maxAge - 0; + if (isNaN(maxAge)) throw new Error('maxAge should be a Number'); + str += '; Max-Age=' + Math.floor(maxAge); } -}; -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); + if (opt.domain) { + if (!fieldContentRegExp.test(opt.domain)) { + throw new TypeError('option domain is invalid'); + } -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); + str += '; Domain=' + opt.domain; } -}; -assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); + if (opt.path) { + if (!fieldContentRegExp.test(opt.path)) { + throw new TypeError('option path is invalid'); + } + + str += '; Path=' + opt.path; } -}; -function _deepEqual(actual, expected, strict, memos) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - } else if (isBuffer(actual) && isBuffer(expected)) { - return compare(actual, expected) === 0; + if (opt.expires) { + if (typeof opt.expires.toUTCString !== 'function') { + throw new TypeError('option expires is invalid'); + } - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (util.isDate(actual) && util.isDate(expected)) { - return actual.getTime() === expected.getTime(); + str += '; Expires=' + opt.expires.toUTCString(); + } - // 7.3 If the expected value is a RegExp object, the actual value is - // equivalent if it is also a RegExp object with the same source and - // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). - } else if (util.isRegExp(actual) && util.isRegExp(expected)) { - return actual.source === expected.source && - actual.global === expected.global && - actual.multiline === expected.multiline && - actual.lastIndex === expected.lastIndex && - actual.ignoreCase === expected.ignoreCase; + if (opt.httpOnly) str += '; HttpOnly'; + if (opt.secure) str += '; Secure'; - // 7.4. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if ((actual === null || typeof actual !== 'object') && - (expected === null || typeof expected !== 'object')) { - return strict ? actual === expected : actual == expected; + if (opt.sameSite) { + var sameSite = typeof opt.sameSite === 'string' ? opt.sameSite.toLowerCase() : opt.sameSite; - // If both values are instances of typed arrays, wrap their underlying - // ArrayBuffers in a Buffer each to increase performance - // This optimization requires the arrays to have the same type as checked by - // Object.prototype.toString (aka pToString). Never perform binary - // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their - // bit patterns are not identical. - } else if (isView(actual) && isView(expected) && - pToString(actual) === pToString(expected) && - !(actual instanceof Float32Array || - actual instanceof Float64Array)) { - return compare(new Uint8Array(actual.buffer), - new Uint8Array(expected.buffer)) === 0; + switch (sameSite) { + case true: + str += '; SameSite=Strict'; + break; - // 7.5 For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else if (isBuffer(actual) !== isBuffer(expected)) { - return false; - } else { - memos = memos || {actual: [], expected: []}; + case 'lax': + str += '; SameSite=Lax'; + break; - var actualIndex = memos.actual.indexOf(actual); - if (actualIndex !== -1) { - if (actualIndex === memos.expected.indexOf(expected)) { - return true; - } - } + case 'strict': + str += '; SameSite=Strict'; + break; - memos.actual.push(actual); - memos.expected.push(expected); + case 'none': + str += '; SameSite=None'; + break; - return objEquiv(actual, expected, strict, memos); + default: + throw new TypeError('option sameSite is invalid'); + } } -} -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} + return str; +}; -function objEquiv(a, b, strict, actualVisitedObjects) { - if (a === null || a === undefined || b === null || b === undefined) - return false; - // if one is a primitive, the other must be same - if (util.isPrimitive(a) || util.isPrimitive(b)) - return a === b; - if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) - return false; - var aIsArgs = isArguments(a); - var bIsArgs = isArguments(b); - if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) - return false; - if (aIsArgs) { - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b, strict); - } - var ka = objectKeys(a); - var kb = objectKeys(b); - var key, i; - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length !== kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] !== kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) - return false; - } - return true; -} +var cookie = { + create: function create(name, value, minutes, domain) { + var cookieOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : { + path: '/', + sameSite: 'strict' + }; -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); + if (minutes) { + cookieOptions.expires = new Date(); + cookieOptions.expires.setTime(cookieOptions.expires.getTime() + minutes * 60 * 1000); + } -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } -}; + if (domain) cookieOptions.domain = domain; + document.cookie = serializeCookie(name, encodeURIComponent(value), cookieOptions); + }, + read: function read(name) { + var nameEQ = name + '='; + var ca = document.cookie.split(';'); -assert.notDeepStrictEqual = notDeepStrictEqual; -function notDeepStrictEqual(actual, expected, message) { - if (_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); - } -} + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1, c.length); + } -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); + if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); + } -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); + return null; + }, + remove: function remove(name) { + this.create(name, '', -1); } }; +var cookie$1 = { + name: 'cookie', + lookup: function lookup(options) { + var found; -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + if (options.lookupCookie && typeof document !== 'undefined') { + var c = cookie.read(options.lookupCookie); + if (c) found = c; + } -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); + return found; + }, + cacheUserLanguage: function cacheUserLanguage(lng, options) { + if (options.lookupCookie && typeof document !== 'undefined') { + cookie.create(options.lookupCookie, lng, options.cookieMinutes, options.cookieDomain, options.cookieOptions); + } } }; -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } +var querystring = { + name: 'querystring', + lookup: function lookup(options) { + var found; - if (Object.prototype.toString.call(expected) == '[object RegExp]') { - return expected.test(actual); - } + if (typeof window !== 'undefined') { + var query = window.location.search.substring(1); + var params = query.split('&'); - try { - if (actual instanceof expected) { - return true; + for (var i = 0; i < params.length; i++) { + var pos = params[i].indexOf('='); + + if (pos > 0) { + var key = params[i].substring(0, pos); + + if (key === options.lookupQuerystring) { + found = params[i].substring(pos + 1); + } + } + } } - } catch (e) { - // Ignore. The instanceof check doesn't work for arrow functions. - } - if (Error.isPrototypeOf(expected)) { - return false; + return found; } +}; - return expected.call({}, actual) === true; -} +var hasLocalStorageSupport = null; + +var localStorageAvailable = function localStorageAvailable() { + if (hasLocalStorageSupport !== null) return hasLocalStorageSupport; -function _tryBlock(block) { - var error; try { - block(); + hasLocalStorageSupport = window !== 'undefined' && window.localStorage !== null; + var testKey = 'i18next.translate.boo'; + window.localStorage.setItem(testKey, 'foo'); + window.localStorage.removeItem(testKey); } catch (e) { - error = e; - } - return error; -} - -function _throws(shouldThrow, block, expected, message) { - var actual; - - if (typeof block !== 'function') { - throw new TypeError('"block" argument must be a function'); + hasLocalStorageSupport = false; } - if (typeof expected === 'string') { - message = expected; - expected = null; - } + return hasLocalStorageSupport; +}; - actual = _tryBlock(block); +var localStorage = { + name: 'localStorage', + lookup: function lookup(options) { + var found; - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); + if (options.lookupLocalStorage && localStorageAvailable()) { + var lng = window.localStorage.getItem(options.lookupLocalStorage); + if (lng) found = lng; + } - if (shouldThrow && !actual) { - fail(actual, expected, 'Missing expected exception' + message); + return found; + }, + cacheUserLanguage: function cacheUserLanguage(lng, options) { + if (options.lookupLocalStorage && localStorageAvailable()) { + window.localStorage.setItem(options.lookupLocalStorage, lng); + } } +}; - var userProvidedMessage = typeof message === 'string'; - var isUnwantedException = !shouldThrow && util.isError(actual); - var isUnexpectedException = !shouldThrow && actual && !expected; +var hasSessionStorageSupport = null; - if ((isUnwantedException && - userProvidedMessage && - expectedException(actual, expected)) || - isUnexpectedException) { - fail(actual, expected, 'Got unwanted exception' + message); - } +var sessionStorageAvailable = function sessionStorageAvailable() { + if (hasSessionStorageSupport !== null) return hasSessionStorageSupport; - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; + try { + hasSessionStorageSupport = window !== 'undefined' && window.sessionStorage !== null; + var testKey = 'i18next.translate.boo'; + window.sessionStorage.setItem(testKey, 'foo'); + window.sessionStorage.removeItem(testKey); + } catch (e) { + hasSessionStorageSupport = false; } -} - -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws(true, block, error, message); + return hasSessionStorageSupport; }; -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { - _throws(false, block, error, message); -}; +var sessionStorage = { + name: 'sessionStorage', + lookup: function lookup(options) { + var found; -assert.ifError = function(err) { if (err) throw err; }; + if (options.lookupSessionStorage && sessionStorageAvailable()) { + var lng = window.sessionStorage.getItem(options.lookupSessionStorage); + if (lng) found = lng; + } -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - if (hasOwn.call(obj, key)) keys.push(key); + return found; + }, + cacheUserLanguage: function cacheUserLanguage(lng, options) { + if (options.lookupSessionStorage && sessionStorageAvailable()) { + window.sessionStorage.setItem(options.lookupSessionStorage, lng); + } } - return keys; }; -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack-stream/node_modules/webpack/buildin/global.js */ "./node_modules/webpack-stream/node_modules/webpack/buildin/global.js"))) +var navigator$1 = { + name: 'navigator', + lookup: function lookup(options) { + var found = []; -/***/ }), + if (typeof navigator !== 'undefined') { + if (navigator.languages) { + // chrome only; not an array, so can't use .push.apply instead of iterating + for (var i = 0; i < navigator.languages.length; i++) { + found.push(navigator.languages[i]); + } + } -/***/ "./node_modules/dct/index.js": -/*!***********************************!*\ - !*** ./node_modules/dct/index.js ***! - \***********************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { + if (navigator.userLanguage) { + found.push(navigator.userLanguage); + } -module.exports = __webpack_require__(/*! ./src/dct.js */ "./node_modules/dct/src/dct.js"); + if (navigator.language) { + found.push(navigator.language); + } + } + return found.length > 0 ? found : undefined; + } +}; -/***/ }), +var htmlTag = { + name: 'htmlTag', + lookup: function lookup(options) { + var found; + var htmlTag = options.htmlTag || (typeof document !== 'undefined' ? document.documentElement : null); -/***/ "./node_modules/dct/src/dct.js": -/*!*************************************!*\ - !*** ./node_modules/dct/src/dct.js ***! - \*************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { + if (htmlTag && typeof htmlTag.getAttribute === 'function') { + found = htmlTag.getAttribute('lang'); + } -/*===========================================================================*\ - * Discrete Cosine Transform - * - * (c) Vail Systems. Joshua Jung and Ben Bryan. 2015 - * - * This code is not designed to be highly optimized but as an educational - * tool to understand the Mel-scale and its related coefficients used in - * human speech analysis. -\*===========================================================================*/ -var cosMap = null; + return found; + } +}; -// Builds a cosine map for the given input size. This allows multiple input sizes to be memoized automagically -// if you want to run the DCT over and over. -var memoizeCosines = function(N) { - cosMap = cosMap || {}; - cosMap[N] = new Array(N*N); +var path = { + name: 'path', + lookup: function lookup(options) { + var found; - var PI_N = Math.PI / N; + if (typeof window !== 'undefined') { + var language = window.location.pathname.match(/\/([a-zA-Z-]*)/g); - for (var k = 0; k < N; k++) { - for (var n = 0; n < N; n++) { - cosMap[N][n + (k * N)] = Math.cos(PI_N * (n + 0.5) * k); + if (language instanceof Array) { + if (typeof options.lookupFromPathIndex === 'number') { + if (typeof language[options.lookupFromPathIndex] !== 'string') { + return undefined; + } + + found = language[options.lookupFromPathIndex].replace('/', ''); + } else { + found = language[0].replace('/', ''); + } + } } + + return found; } }; -function dct(signal, scale) { - var L = signal.length; - scale = scale || 2; +var subdomain = { + name: 'subdomain', + lookup: function lookup(options) { + var found; - if (!cosMap || !cosMap[L]) memoizeCosines(L); + if (typeof window !== 'undefined') { + var language = window.location.href.match(/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/gi); - var coefficients = signal.map(function () {return 0;}); + if (language instanceof Array) { + if (typeof options.lookupFromSubdomainIndex === 'number') { + found = language[options.lookupFromSubdomainIndex].replace('http://', '').replace('https://', '').replace('.', ''); + } else { + found = language[0].replace('http://', '').replace('https://', '').replace('.', ''); + } + } + } - return coefficients.map(function (__, ix) { - return scale * signal.reduce(function (prev, cur, ix_, arr) { - return prev + (cur * cosMap[L][ix_ + (ix * L)]); - }, 0); - }); + return found; + } }; -module.exports = dct; - - -/***/ }), +function getDefaults() { + return { + order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag'], + lookupQuerystring: 'lng', + lookupCookie: 'i18next', + lookupLocalStorage: 'i18nextLng', + lookupSessionStorage: 'i18nextLng', + // cache user language + caches: ['localStorage'], + excludeCacheFor: ['cimode'] //cookieMinutes: 10, + //cookieDomain: 'myDomain' -/***/ "./node_modules/fftjs/dist/fft.js": -/*!****************************************!*\ - !*** ./node_modules/fftjs/dist/fft.js ***! - \****************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { + }; +} -"use strict"; +var Browser = /*#__PURE__*/function () { + function Browser(services) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + _classCallCheck__default['default'](this, Browser); -var utils = __webpack_require__(/*! ./utils */ "./node_modules/fftjs/dist/utils.js"); + this.type = 'languageDetector'; + this.detectors = {}; + this.init(services, options); + } -// real to complex fft -var fft = function fft(signal) { + _createClass__default['default'](Browser, [{ + key: "init", + value: function init(services) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var i18nOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + this.services = services; + this.options = defaults(options, this.options || {}, getDefaults()); // backwards compatibility - var complexSignal = {}; + if (this.options.lookupFromUrlIndex) this.options.lookupFromPathIndex = this.options.lookupFromUrlIndex; + this.i18nOptions = i18nOptions; + this.addDetector(cookie$1); + this.addDetector(querystring); + this.addDetector(localStorage); + this.addDetector(sessionStorage); + this.addDetector(navigator$1); + this.addDetector(htmlTag); + this.addDetector(path); + this.addDetector(subdomain); + } + }, { + key: "addDetector", + value: function addDetector(detector) { + this.detectors[detector.name] = detector; + } + }, { + key: "detect", + value: function detect(detectionOrder) { + var _this = this; - if (signal.real === undefined || signal.imag === undefined) { - complexSignal = utils.constructComplexArray(signal); - } else { - complexSignal.real = signal.real.slice(); - complexSignal.imag = signal.imag.slice(); - } + if (!detectionOrder) detectionOrder = this.options.order; + var detected = []; + detectionOrder.forEach(function (detectorName) { + if (_this.detectors[detectorName]) { + var lookup = _this.detectors[detectorName].lookup(_this.options); - var N = complexSignal.real.length; - var logN = Math.log2(N); + if (lookup && typeof lookup === 'string') lookup = [lookup]; + if (lookup) detected = detected.concat(lookup); + } + }); + if (this.services.languageUtils.getBestMatchFromCodes) return detected; // new i18next v19.5.0 - if (Math.round(logN) != logN) throw new Error('Input size must be a power of 2.'); + return detected.length > 0 ? detected[0] : null; // a little backward compatibility + } + }, { + key: "cacheUserLanguage", + value: function cacheUserLanguage(lng, caches) { + var _this2 = this; - if (complexSignal.real.length != complexSignal.imag.length) { - throw new Error('Real and imaginary components must have the same length.'); - } + if (!caches) caches = this.options.caches; + if (!caches) return; + if (this.options.excludeCacheFor && this.options.excludeCacheFor.indexOf(lng) > -1) return; + caches.forEach(function (cacheName) { + if (_this2.detectors[cacheName]) _this2.detectors[cacheName].cacheUserLanguage(lng, _this2.options); + }); + } + }]); - var bitReversedIndices = utils.bitReverseArray(N); + return Browser; +}(); - // sort array - var ordered = { - 'real': [], - 'imag': [] - }; +Browser.type = 'languageDetector'; - for (var i = 0; i < N; i++) { - ordered.real[bitReversedIndices[i]] = complexSignal.real[i]; - ordered.imag[bitReversedIndices[i]] = complexSignal.imag[i]; - } +module.exports = Browser; - for (var _i = 0; _i < N; _i++) { - complexSignal.real[_i] = ordered.real[_i]; - complexSignal.imag[_i] = ordered.imag[_i]; - } - // iterate over the number of stages - for (var n = 1; n <= logN; n++) { - var currN = Math.pow(2, n); +},{"@babel/runtime/helpers/classCallCheck":11,"@babel/runtime/helpers/createClass":12}],89:[function(require,module,exports){ +'use strict'; - // find twiddle factors - for (var k = 0; k < currN / 2; k++) { - var twiddle = utils.euler(k, currN); +var _typeof = require('@babel/runtime/helpers/typeof'); +var _classCallCheck = require('@babel/runtime/helpers/classCallCheck'); +var _createClass = require('@babel/runtime/helpers/createClass'); +var _assertThisInitialized = require('@babel/runtime/helpers/assertThisInitialized'); +var _inherits = require('@babel/runtime/helpers/inherits'); +var _possibleConstructorReturn = require('@babel/runtime/helpers/possibleConstructorReturn'); +var _getPrototypeOf = require('@babel/runtime/helpers/getPrototypeOf'); +var _defineProperty = require('@babel/runtime/helpers/defineProperty'); +var _toArray = require('@babel/runtime/helpers/toArray'); - // on each block of FT, implement the butterfly diagram - for (var m = 0; m < N / currN; m++) { - var currEvenIndex = currN * m + k; - var currOddIndex = currN * m + k + currN / 2; +function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } - var currEvenIndexSample = { - 'real': complexSignal.real[currEvenIndex], - 'imag': complexSignal.imag[currEvenIndex] - }; - var currOddIndexSample = { - 'real': complexSignal.real[currOddIndex], - 'imag': complexSignal.imag[currOddIndex] - }; +var _typeof__default = /*#__PURE__*/_interopDefaultLegacy(_typeof); +var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck); +var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass); +var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized); +var _inherits__default = /*#__PURE__*/_interopDefaultLegacy(_inherits); +var _possibleConstructorReturn__default = /*#__PURE__*/_interopDefaultLegacy(_possibleConstructorReturn); +var _getPrototypeOf__default = /*#__PURE__*/_interopDefaultLegacy(_getPrototypeOf); +var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty); +var _toArray__default = /*#__PURE__*/_interopDefaultLegacy(_toArray); - var odd = utils.multiply(twiddle, currOddIndexSample); +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } - var subtractionResult = utils.subtract(currEvenIndexSample, odd); - complexSignal.real[currOddIndex] = subtractionResult.real; - complexSignal.imag[currOddIndex] = subtractionResult.imag; +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - var additionResult = utils.add(odd, currEvenIndexSample); - complexSignal.real[currEvenIndex] = additionResult.real; - complexSignal.imag[currEvenIndex] = additionResult.imag; - } - } +var consoleLogger = { + type: 'logger', + log: function log(args) { + this.output('log', args); + }, + warn: function warn(args) { + this.output('warn', args); + }, + error: function error(args) { + this.output('error', args); + }, + output: function output(type, args) { + if (console && console[type]) console[type].apply(console, args); } - - return complexSignal; }; -// complex to real ifft -var ifft = function ifft(signal) { +var Logger = function () { + function Logger(concreteLogger) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - if (signal.real === undefined || signal.imag === undefined) { - throw new Error("IFFT only accepts a complex input."); + _classCallCheck__default['default'](this, Logger); + + this.init(concreteLogger, options); } - var N = signal.real.length; + _createClass__default['default'](Logger, [{ + key: "init", + value: function init(concreteLogger) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + this.prefix = options.prefix || 'i18next:'; + this.logger = concreteLogger || consoleLogger; + this.options = options; + this.debug = options.debug; + } + }, { + key: "setDebug", + value: function setDebug(bool) { + this.debug = bool; + } + }, { + key: "log", + value: function log() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } - var complexSignal = { - 'real': [], - 'imag': [] - }; + return this.forward(args, 'log', '', true); + } + }, { + key: "warn", + value: function warn() { + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } - //take complex conjugate in order to be able to use the regular FFT for IFFT - for (var i = 0; i < N; i++) { - var currentSample = { - 'real': signal.real[i], - 'imag': signal.imag[i] - }; + return this.forward(args, 'warn', '', true); + } + }, { + key: "error", + value: function error() { + for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } - var conjugateSample = utils.conj(currentSample); - complexSignal.real[i] = conjugateSample.real; - complexSignal.imag[i] = conjugateSample.imag; - } + return this.forward(args, 'error', ''); + } + }, { + key: "deprecate", + value: function deprecate() { + for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } - //compute - var X = fft(complexSignal); + return this.forward(args, 'warn', 'WARNING DEPRECATED: ', true); + } + }, { + key: "forward", + value: function forward(args, lvl, prefix, debugOnly) { + if (debugOnly && !this.debug) return null; + if (typeof args[0] === 'string') args[0] = "".concat(prefix).concat(this.prefix, " ").concat(args[0]); + return this.logger[lvl](args); + } + }, { + key: "create", + value: function create(moduleName) { + return new Logger(this.logger, _objectSpread(_objectSpread({}, { + prefix: "".concat(this.prefix, ":").concat(moduleName, ":") + }), this.options)); + } + }]); - //normalize - complexSignal.real = X.real.map(function (val) { - return val / N; - }); + return Logger; +}(); - complexSignal.imag = X.imag.map(function (val) { - return val / N; - }); +var baseLogger = new Logger(); - return complexSignal; -}; +var EventEmitter = function () { + function EventEmitter() { + _classCallCheck__default['default'](this, EventEmitter); -module.exports = { - fft: fft, - ifft: ifft -}; + this.observers = {}; + } -/***/ }), + _createClass__default['default'](EventEmitter, [{ + key: "on", + value: function on(events, listener) { + var _this = this; -/***/ "./node_modules/fftjs/dist/utils.js": -/*!******************************************!*\ - !*** ./node_modules/fftjs/dist/utils.js ***! - \******************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { + events.split(' ').forEach(function (event) { + _this.observers[event] = _this.observers[event] || []; -"use strict"; + _this.observers[event].push(listener); + }); + return this; + } + }, { + key: "off", + value: function off(event, listener) { + if (!this.observers[event]) return; + if (!listener) { + delete this.observers[event]; + return; + } -// memoization of the reversal of different lengths. + this.observers[event] = this.observers[event].filter(function (l) { + return l !== listener; + }); + } + }, { + key: "emit", + value: function emit(event) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + if (this.observers[event]) { + var cloned = [].concat(this.observers[event]); + cloned.forEach(function (observer) { + observer.apply(void 0, args); + }); + } -var memoizedReversal = {}; -var memoizedZeroBuffers = {}; + if (this.observers['*']) { + var _cloned = [].concat(this.observers['*']); -var constructComplexArray = function constructComplexArray(signal) { - var complexSignal = {}; + _cloned.forEach(function (observer) { + observer.apply(observer, [event].concat(args)); + }); + } + } + }]); - complexSignal.real = signal.real === undefined ? signal.slice() : signal.real.slice(); + return EventEmitter; +}(); - var bufferSize = complexSignal.real.length; +function defer() { + var res; + var rej; + var promise = new Promise(function (resolve, reject) { + res = resolve; + rej = reject; + }); + promise.resolve = res; + promise.reject = rej; + return promise; +} +function makeString(object) { + if (object == null) return ''; + return '' + object; +} +function copy(a, s, t) { + a.forEach(function (m) { + if (s[m]) t[m] = s[m]; + }); +} - if (memoizedZeroBuffers[bufferSize] === undefined) { - memoizedZeroBuffers[bufferSize] = Array.apply(null, Array(bufferSize)).map(Number.prototype.valueOf, 0); +function getLastOfPath(object, path, Empty) { + function cleanKey(key) { + return key && key.indexOf('###') > -1 ? key.replace(/###/g, '.') : key; } - complexSignal.imag = memoizedZeroBuffers[bufferSize].slice(); - - return complexSignal; -}; + function canNotTraverseDeeper() { + return !object || typeof object === 'string'; + } -var bitReverseArray = function bitReverseArray(N) { - if (memoizedReversal[N] === undefined) { - var maxBinaryLength = (N - 1).toString(2).length; //get the binary length of the largest index. - var templateBinary = '0'.repeat(maxBinaryLength); //create a template binary of that length. - var reversed = {}; - for (var n = 0; n < N; n++) { - var currBinary = n.toString(2); //get binary value of current index. + var stack = typeof path !== 'string' ? [].concat(path) : path.split('.'); - //prepend zeros from template to current binary. This makes binary values of all indices have the same length. - currBinary = templateBinary.substr(currBinary.length) + currBinary; + while (stack.length > 1) { + if (canNotTraverseDeeper()) return {}; + var key = cleanKey(stack.shift()); + if (!object[key] && Empty) object[key] = new Empty(); - currBinary = [].concat(_toConsumableArray(currBinary)).reverse().join(''); //reverse - reversed[n] = parseInt(currBinary, 2); //convert to decimal + if (Object.prototype.hasOwnProperty.call(object, key)) { + object = object[key]; + } else { + object = {}; } - memoizedReversal[N] = reversed; //save } - return memoizedReversal[N]; -}; - -// complex multiplication -var multiply = function multiply(a, b) { - return { - 'real': a.real * b.real - a.imag * b.imag, - 'imag': a.real * b.imag + a.imag * b.real - }; -}; -// complex addition -var add = function add(a, b) { - return { - 'real': a.real + b.real, - 'imag': a.imag + b.imag - }; -}; - -// complex subtraction -var subtract = function subtract(a, b) { + if (canNotTraverseDeeper()) return {}; return { - 'real': a.real - b.real, - 'imag': a.imag - b.imag - }; -}; - -// euler's identity e^x = cos(x) + sin(x) -var euler = function euler(kn, N) { - var x = -2 * Math.PI * kn / N; - return { 'real': Math.cos(x), 'imag': Math.sin(x) }; -}; - -// complex conjugate -var conj = function conj(a) { - a.imag *= -1; - return a; -}; - -module.exports = { - bitReverseArray: bitReverseArray, - multiply: multiply, - add: add, - subtract: subtract, - euler: euler, - conj: conj, - constructComplexArray: constructComplexArray -}; - -/***/ }), - -/***/ "./node_modules/inherits/inherits_browser.js": -/*!***************************************************!*\ - !*** ./node_modules/inherits/inherits_browser.js ***! - \***************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); + obj: object, + k: cleanKey(stack.shift()) }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } } +function setPath(object, path, newValue) { + var _getLastOfPath = getLastOfPath(object, path, Object), + obj = _getLastOfPath.obj, + k = _getLastOfPath.k; -/***/ }), - -/***/ "./node_modules/process/browser.js": -/*!*****************************************!*\ - !*** ./node_modules/process/browser.js ***! - \*****************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { + obj[k] = newValue; +} +function pushPath(object, path, newValue, concat) { + var _getLastOfPath2 = getLastOfPath(object, path, Object), + obj = _getLastOfPath2.obj, + k = _getLastOfPath2.k; -// shim for using process in browser -var process = module.exports = {}; + obj[k] = obj[k] || []; + if (concat) obj[k] = obj[k].concat(newValue); + if (!concat) obj[k].push(newValue); +} +function getPath(object, path) { + var _getLastOfPath3 = getLastOfPath(object, path), + obj = _getLastOfPath3.obj, + k = _getLastOfPath3.k; -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. + if (!obj) return undefined; + return obj[k]; +} +function getPathWithDefaults(data, defaultData, key) { + var value = getPath(data, key); -var cachedSetTimeout; -var cachedClearTimeout; + if (value !== undefined) { + return value; + } -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); + return getPath(defaultData, key); } -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); +function deepExtend(target, source, overwrite) { + for (var prop in source) { + if (prop !== '__proto__' && prop !== 'constructor') { + if (prop in target) { + if (typeof target[prop] === 'string' || target[prop] instanceof String || typeof source[prop] === 'string' || source[prop] instanceof String) { + if (overwrite) target[prop] = source[prop]; + } else { + deepExtend(target[prop], source[prop], overwrite); } + } else { + target[prop] = source[prop]; + } } + } + return target; +} +function regexEscape(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); +} +var _entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/' +}; +function escape(data) { + if (typeof data === 'string') { + return data.replace(/[&<>"'\/]/g, function (s) { + return _entityMap[s]; + }); + } + return data; } -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } +var isIE10 = typeof window !== 'undefined' && window.navigator && window.navigator.userAgent && window.navigator.userAgent.indexOf('MSIE') > -1; +var chars = [' ', ',', '?', '!', ';']; +function looksLikeObjectPath(key, nsSeparator, keySeparator) { + nsSeparator = nsSeparator || ''; + keySeparator = keySeparator || ''; + var possibleChars = chars.filter(function (c) { + return nsSeparator.indexOf(c) < 0 && keySeparator.indexOf(c) < 0; + }); + if (possibleChars.length === 0) return true; + var r = new RegExp("(".concat(possibleChars.map(function (c) { + return c === '?' ? '\\?' : c; + }).join('|'), ")")); + var matched = !r.test(key); + if (!matched) { + var ki = key.indexOf(keySeparator); + if (ki > 0 && !r.test(key.substring(0, ki))) { + matched = true; + } + } + return matched; } -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} +function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; +function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; +function deepFind(obj, path) { + var keySeparator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '.'; + if (!obj) return undefined; + if (obj[path]) return obj[path]; + var paths = path.split(keySeparator); + var current = obj; -function noop() {} + for (var i = 0; i < paths.length; ++i) { + if (!current) return undefined; -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; + if (typeof current[paths[i]] === 'string' && i + 1 < paths.length) { + return undefined; + } -process.listeners = function (name) { return [] } + if (current[paths[i]] === undefined) { + var j = 2; + var p = paths.slice(i, i + j).join(keySeparator); + var mix = current[p]; -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; + while (mix === undefined && paths.length > i + j) { + j++; + p = paths.slice(i, i + j).join(keySeparator); + mix = current[p]; + } -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; + if (mix === undefined) return undefined; + if (path.endsWith(p)) { + if (typeof mix === 'string') return mix; + if (p && typeof mix[p] === 'string') return mix[p]; + } -/***/ }), + var joinedPath = paths.slice(i + j).join(keySeparator); + if (joinedPath) return deepFind(mix, joinedPath, keySeparator); + return undefined; + } -/***/ "./node_modules/webpack-stream/node_modules/util/support/isBufferBrowser.js": -/*!**********************************************************************************!*\ - !*** ./node_modules/webpack-stream/node_modules/util/support/isBufferBrowser.js ***! - \**********************************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { + current = current[paths[i]]; + } -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; + return current; } -/***/ }), +var ResourceStore = function (_EventEmitter) { + _inherits__default['default'](ResourceStore, _EventEmitter); -/***/ "./node_modules/webpack-stream/node_modules/util/util.js": -/*!***************************************************************!*\ - !*** ./node_modules/webpack-stream/node_modules/util/util.js ***! - \***************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { + var _super = _createSuper(ResourceStore); -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. + function ResourceStore(data) { + var _this; -var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || - function getOwnPropertyDescriptors(obj) { - var keys = Object.keys(obj); - var descriptors = {}; - for (var i = 0; i < keys.length; i++) { - descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]); - } - return descriptors; - }; + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + ns: ['translation'], + defaultNS: 'translation' + }; -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } + _classCallCheck__default['default'](this, ResourceStore); - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; + _this = _super.call(this); + + if (isIE10) { + EventEmitter.call(_assertThisInitialized__default['default'](_this)); } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); + + _this.data = data || {}; + _this.options = options; + + if (_this.options.keySeparator === undefined) { + _this.options.keySeparator = '.'; } - } - return str; -}; + if (_this.options.ignoreJSONStructure === undefined) { + _this.options.ignoreJSONStructure = true; + } -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - if (typeof process !== 'undefined' && process.noDeprecation === true) { - return fn; + return _this; } - // Allow for deprecating things in the process of starting up. - if (typeof process === 'undefined') { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } + _createClass__default['default'](ResourceStore, [{ + key: "addNamespaces", + value: function addNamespaces(ns) { + if (this.options.ns.indexOf(ns) < 0) { + this.options.ns.push(ns); + } + } + }, { + key: "removeNamespaces", + value: function removeNamespaces(ns) { + var index = this.options.ns.indexOf(ns); - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); + if (index > -1) { + this.options.ns.splice(index, 1); } - warned = true; } - return fn.apply(this, arguments); - } + }, { + key: "getResource", + value: function getResource(lng, ns, key) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; + var ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure; + var path = [lng, ns]; + if (key && typeof key !== 'string') path = path.concat(key); + if (key && typeof key === 'string') path = path.concat(keySeparator ? key.split(keySeparator) : key); - return deprecated; -}; + if (lng.indexOf('.') > -1) { + path = lng.split('.'); + } + var result = getPath(this.data, path); + if (result || !ignoreJSONStructure || typeof key !== 'string') return result; + return deepFind(this.data && this.data[lng] && this.data[lng][ns], key, keySeparator); + } + }, { + key: "addResource", + value: function addResource(lng, ns, key, value) { + var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : { + silent: false + }; + var keySeparator = this.options.keySeparator; + if (keySeparator === undefined) keySeparator = '.'; + var path = [lng, ns]; + if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key); -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); + if (lng.indexOf('.') > -1) { + path = lng.split('.'); + value = ns; + ns = path[1]; + } + + this.addNamespaces(ns); + setPath(this.data, path, value); + if (!options.silent) this.emit('added', lng, ns, key, value); + } + }, { + key: "addResources", + value: function addResources(lng, ns, resources) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : { + silent: false }; - } else { - debugs[set] = function() {}; + + for (var m in resources) { + if (typeof resources[m] === 'string' || Object.prototype.toString.apply(resources[m]) === '[object Array]') this.addResource(lng, ns, m, resources[m], { + silent: true + }); + } + + if (!options.silent) this.emit('added', lng, ns, resources); } - } - return debugs[set]; -}; + }, { + key: "addResourceBundle", + value: function addResourceBundle(lng, ns, resources, deep, overwrite) { + var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : { + silent: false + }; + var path = [lng, ns]; + if (lng.indexOf('.') > -1) { + path = lng.split('.'); + deep = resources; + resources = ns; + ns = path[1]; + } -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; + this.addNamespaces(ns); + var pack = getPath(this.data, path) || {}; + if (deep) { + deepExtend(pack, resources, overwrite); + } else { + pack = _objectSpread$1(_objectSpread$1({}, pack), resources); + } -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; + setPath(this.data, path, pack); + if (!options.silent) this.emit('added', lng, ns, resources); + } + }, { + key: "removeResourceBundle", + value: function removeResourceBundle(lng, ns) { + if (this.hasResourceBundle(lng, ns)) { + delete this.data[lng][ns]; + } -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; + this.removeNamespaces(ns); + this.emit('removed', lng, ns); + } + }, { + key: "hasResourceBundle", + value: function hasResourceBundle(lng, ns) { + return this.getResource(lng, ns) !== undefined; + } + }, { + key: "getResourceBundle", + value: function getResourceBundle(lng, ns) { + if (!ns) ns = this.options.defaultNS; + if (this.options.compatibilityAPI === 'v1') return _objectSpread$1(_objectSpread$1({}, {}), this.getResource(lng, ns)); + return this.getResource(lng, ns); + } + }, { + key: "getDataByLanguage", + value: function getDataByLanguage(lng) { + return this.data[lng]; + } + }, { + key: "hasLanguageSomeTranslations", + value: function hasLanguageSomeTranslations(lng) { + var data = this.getDataByLanguage(lng); + var n = data && Object.keys(data) || []; + return !!n.find(function (v) { + return data[v] && Object.keys(data[v]).length > 0; + }); + } + }, { + key: "toJSON", + value: function toJSON() { + return this.data; + } + }]); + return ResourceStore; +}(EventEmitter); -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; +var postProcessor = { + processors: {}, + addPostProcessor: function addPostProcessor(module) { + this.processors[module.name] = module; + }, + handle: function handle(processors, value, key, options, translator) { + var _this = this; - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; + processors.forEach(function (processor) { + if (_this.processors[processor]) value = _this.processors[processor].process(value, key, options, translator); + }); + return value; } -} +}; +function ownKeys$2(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } -function stylizeNoColor(str, styleType) { - return str; -} +function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$2(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$2(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } +function _createSuper$1(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } -function arrayToHash(array) { - var hash = {}; +function _isNativeReflectConstruct$1() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +var checkedLoadedFor = {}; - array.forEach(function(val, idx) { - hash[val] = true; - }); +var Translator = function (_EventEmitter) { + _inherits__default['default'](Translator, _EventEmitter); - return hash; -} + var _super = _createSuper$1(Translator); + function Translator(services) { + var _this; -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } + _classCallCheck__default['default'](this, Translator); - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); + _this = _super.call(this); - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } + if (isIE10) { + EventEmitter.call(_assertThisInitialized__default['default'](_this)); + } - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } + copy(['resourceStore', 'languageUtils', 'pluralResolver', 'interpolator', 'backendConnector', 'i18nFormat', 'utils'], services, _assertThisInitialized__default['default'](_this)); + _this.options = options; - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); + if (_this.options.keySeparator === undefined) { + _this.options.keySeparator = '.'; } - } - - var base = '', array = false, braces = ['{', '}']; - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; + _this.logger = baseLogger.create('translator'); + return _this; } - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } + _createClass__default['default'](Translator, [{ + key: "changeLanguage", + value: function changeLanguage(lng) { + if (lng) this.language = lng; + } + }, { + key: "exists", + value: function exists(key) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + interpolation: {} + }; - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } + if (key === undefined || key === null) { + return false; + } - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } + var resolved = this.resolve(key, options); + return resolved && resolved.res !== undefined; + } + }, { + key: "extractFromKey", + value: function extractFromKey(key, options) { + var nsSeparator = options.nsSeparator !== undefined ? options.nsSeparator : this.options.nsSeparator; + if (nsSeparator === undefined) nsSeparator = ':'; + var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; + var namespaces = options.ns || this.options.defaultNS || []; + var wouldCheckForNsInKey = nsSeparator && key.indexOf(nsSeparator) > -1; + var seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !options.keySeparator && !this.options.userDefinedNsSeparator && !options.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator); - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } + if (wouldCheckForNsInKey && !seemsNaturalLanguage) { + var m = key.match(this.interpolator.nestingRegexp); - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } + if (m && m.length > 0) { + return { + key: key, + namespaces: namespaces + }; + } - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); + var parts = key.split(nsSeparator); + if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.indexOf(parts[0]) > -1) namespaces = parts.shift(); + key = parts.join(keySeparator); + } + + if (typeof namespaces === 'string') namespaces = [namespaces]; + return { + key: key, + namespaces: namespaces + }; } - } + }, { + key: "translate", + value: function translate(keys, options, lastKey) { + var _this2 = this; - ctx.seen.push(value); + if (_typeof__default['default'](options) !== 'object' && this.options.overloadTranslationOptionHandler) { + options = this.options.overloadTranslationOptionHandler(arguments); + } - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } + if (!options) options = {}; + if (keys === undefined || keys === null) return ''; + if (!Array.isArray(keys)) keys = [String(keys)]; + var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; - ctx.seen.pop(); + var _this$extractFromKey = this.extractFromKey(keys[keys.length - 1], options), + key = _this$extractFromKey.key, + namespaces = _this$extractFromKey.namespaces; - return reduceToSingleString(output, base, braces); -} + var namespace = namespaces[namespaces.length - 1]; + var lng = options.lng || this.language; + var appendNamespaceToCIMode = options.appendNamespaceToCIMode || this.options.appendNamespaceToCIMode; + if (lng && lng.toLowerCase() === 'cimode') { + if (appendNamespaceToCIMode) { + var nsSeparator = options.nsSeparator || this.options.nsSeparator; + return namespace + nsSeparator + key; + } -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} + return key; + } + var resolved = this.resolve(keys, options); + var res = resolved && resolved.res; + var resUsedKey = resolved && resolved.usedKey || key; + var resExactUsedKey = resolved && resolved.exactUsedKey || key; + var resType = Object.prototype.toString.apply(res); + var noObject = ['[object Number]', '[object Function]', '[object RegExp]']; + var joinArrays = options.joinArrays !== undefined ? options.joinArrays : this.options.joinArrays; + var handleAsObjectInI18nFormat = !this.i18nFormat || this.i18nFormat.handleAsObject; + var handleAsObject = typeof res !== 'string' && typeof res !== 'boolean' && typeof res !== 'number'; -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} + if (handleAsObjectInI18nFormat && res && handleAsObject && noObject.indexOf(resType) < 0 && !(typeof joinArrays === 'string' && resType === '[object Array]')) { + if (!options.returnObjects && !this.options.returnObjects) { + if (!this.options.returnedObjectHandler) { + this.logger.warn('accessing an object - but returnObjects options is not enabled!'); + } + return this.options.returnedObjectHandler ? this.options.returnedObjectHandler(resUsedKey, res, _objectSpread$2(_objectSpread$2({}, options), {}, { + ns: namespaces + })) : "key '".concat(key, " (").concat(this.language, ")' returned an object instead of string."); + } -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} + if (keySeparator) { + var resTypeIsArray = resType === '[object Array]'; + var copy = resTypeIsArray ? [] : {}; + var newKeyToUse = resTypeIsArray ? resExactUsedKey : resUsedKey; + for (var m in res) { + if (Object.prototype.hasOwnProperty.call(res, m)) { + var deepKey = "".concat(newKeyToUse).concat(keySeparator).concat(m); + copy[m] = this.translate(deepKey, _objectSpread$2(_objectSpread$2({}, options), { + joinArrays: false, + ns: namespaces + })); + if (copy[m] === deepKey) copy[m] = res[m]; + } + } -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); + res = copy; + } + } else if (handleAsObjectInI18nFormat && typeof joinArrays === 'string' && resType === '[object Array]') { + res = res.join(joinArrays); + if (res) res = this.extendTranslation(res, keys, options, lastKey); } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); + var usedDefault = false; + var usedKey = false; + var needsPluralHandling = options.count !== undefined && typeof options.count !== 'string'; + var hasDefaultValue = Translator.hasDefaultValue(options); + var defaultValueSuffix = needsPluralHandling ? this.pluralResolver.getSuffix(lng, options.count, options) : ''; + var defaultValue = options["defaultValue".concat(defaultValueSuffix)] || options.defaultValue; + + if (!this.isValidLookup(res) && hasDefaultValue) { + usedDefault = true; + res = defaultValue; } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - return name + ': ' + str; -} + if (!this.isValidLookup(res)) { + usedKey = true; + res = key; + } + var missingKeyNoValueFallbackToKey = options.missingKeyNoValueFallbackToKey || this.options.missingKeyNoValueFallbackToKey; + var resForMissing = missingKeyNoValueFallbackToKey && usedKey ? undefined : res; + var updateMissing = hasDefaultValue && defaultValue !== res && this.options.updateMissing; -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); + if (usedKey || usedDefault || updateMissing) { + this.logger.log(updateMissing ? 'updateKey' : 'missingKey', lng, namespace, key, updateMissing ? defaultValue : res); - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } + if (keySeparator) { + var fk = this.resolve(key, _objectSpread$2(_objectSpread$2({}, options), {}, { + keySeparator: false + })); + if (fk && fk.res) this.logger.warn('Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.'); + } - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} + var lngs = []; + var fallbackLngs = this.languageUtils.getFallbackCodes(this.options.fallbackLng, options.lng || this.language); + if (this.options.saveMissingTo === 'fallback' && fallbackLngs && fallbackLngs[0]) { + for (var i = 0; i < fallbackLngs.length; i++) { + lngs.push(fallbackLngs[i]); + } + } else if (this.options.saveMissingTo === 'all') { + lngs = this.languageUtils.toResolveHierarchy(options.lng || this.language); + } else { + lngs.push(options.lng || this.language); + } -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; + var send = function send(l, k, specificDefaultValue) { + var defaultForMissing = hasDefaultValue && specificDefaultValue !== res ? specificDefaultValue : resForMissing; -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; + if (_this2.options.missingKeyHandler) { + _this2.options.missingKeyHandler(l, namespace, k, defaultForMissing, updateMissing, options); + } else if (_this2.backendConnector && _this2.backendConnector.saveMissing) { + _this2.backendConnector.saveMissing(l, namespace, k, defaultForMissing, updateMissing, options); + } -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; + _this2.emit('missingKey', l, namespace, k, res); + }; -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; + if (this.options.saveMissing) { + if (this.options.saveMissingPlurals && needsPluralHandling) { + lngs.forEach(function (language) { + _this2.pluralResolver.getSuffixes(language).forEach(function (suffix) { + send([language], key + suffix, options["defaultValue".concat(suffix)] || defaultValue); + }); + }); + } else { + send(lngs, key, defaultValue); + } + } + } -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; + res = this.extendTranslation(res, keys, options, resolved, lastKey); + if (usedKey && res === key && this.options.appendNamespaceToMissingKey) res = "".concat(namespace, ":").concat(key); + if ((usedKey || usedDefault) && this.options.parseMissingKeyHandler) res = this.options.parseMissingKeyHandler(res); + } -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; + return res; + } + }, { + key: "extendTranslation", + value: function extendTranslation(res, key, options, resolved, lastKey) { + var _this3 = this; -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; + if (this.i18nFormat && this.i18nFormat.parse) { + res = this.i18nFormat.parse(res, options, resolved.usedLng, resolved.usedNS, resolved.usedKey, { + resolved: resolved + }); + } else if (!options.skipInterpolation) { + if (options.interpolation) this.interpolator.init(_objectSpread$2(_objectSpread$2({}, options), { + interpolation: _objectSpread$2(_objectSpread$2({}, this.options.interpolation), options.interpolation) + })); + var skipOnVariables = typeof res === 'string' && (options.interpolation && options.interpolation.skipOnVariables || this.options.interpolation.skipOnVariables); + var nestBef; -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; + if (skipOnVariables) { + var nb = res.match(this.interpolator.nestingRegexp); + nestBef = nb && nb.length; + } -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; + var data = options.replace && typeof options.replace !== 'string' ? options.replace : options; + if (this.options.interpolation.defaultVariables) data = _objectSpread$2(_objectSpread$2({}, this.options.interpolation.defaultVariables), data); + res = this.interpolator.interpolate(res, data, options.lng || this.language, options); -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; + if (skipOnVariables) { + var na = res.match(this.interpolator.nestingRegexp); + var nestAft = na && na.length; + if (nestBef < nestAft) options.nest = false; + } -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; + if (options.nest !== false) res = this.interpolator.nest(res, function () { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; + if (lastKey && lastKey[0] === args[0] && !options.context) { + _this3.logger.warn("It seems you are nesting recursively key: ".concat(args[0], " in key: ").concat(key[0])); -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; + return null; + } -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; + return _this3.translate.apply(_this3, args.concat([key])); + }, options); + if (options.interpolation) this.interpolator.reset(); + } -exports.isBuffer = __webpack_require__(/*! ./support/isBuffer */ "./node_modules/webpack-stream/node_modules/util/support/isBufferBrowser.js"); + var postProcess = options.postProcess || this.options.postProcess; + var postProcessorNames = typeof postProcess === 'string' ? [postProcess] : postProcess; -function objectToString(o) { - return Object.prototype.toString.call(o); -} + if (res !== undefined && res !== null && postProcessorNames && postProcessorNames.length && options.applyPostProcessor !== false) { + res = postProcessor.handle(postProcessorNames, res, key, this.options && this.options.postProcessPassResolved ? _objectSpread$2({ + i18nResolved: resolved + }, options) : options, this); + } + return res; + } + }, { + key: "resolve", + value: function resolve(keys) { + var _this4 = this; -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var found; + var usedKey; + var exactUsedKey; + var usedLng; + var usedNS; + if (typeof keys === 'string') keys = [keys]; + keys.forEach(function (k) { + if (_this4.isValidLookup(found)) return; + var extracted = _this4.extractFromKey(k, options); -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; + var key = extracted.key; + usedKey = key; + var namespaces = extracted.namespaces; + if (_this4.options.fallbackNS) namespaces = namespaces.concat(_this4.options.fallbackNS); + var needsPluralHandling = options.count !== undefined && typeof options.count !== 'string'; -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} + var needsZeroSuffixLookup = needsPluralHandling && !options.ordinal && options.count === 0 && _this4.pluralResolver.shouldUseIntlApi(); + var needsContextHandling = options.context !== undefined && (typeof options.context === 'string' || typeof options.context === 'number') && options.context !== ''; + var codes = options.lngs ? options.lngs : _this4.languageUtils.toResolveHierarchy(options.lng || _this4.language, options.fallbackLng); + namespaces.forEach(function (ns) { + if (_this4.isValidLookup(found)) return; + usedNS = ns; -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; + if (!checkedLoadedFor["".concat(codes[0], "-").concat(ns)] && _this4.utils && _this4.utils.hasLoadedNamespace && !_this4.utils.hasLoadedNamespace(usedNS)) { + checkedLoadedFor["".concat(codes[0], "-").concat(ns)] = true; + _this4.logger.warn("key \"".concat(usedKey, "\" for languages \"").concat(codes.join(', '), "\" won't get resolved as namespace \"").concat(usedNS, "\" was not yet loaded"), 'This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!'); + } -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"); + codes.forEach(function (code) { + if (_this4.isValidLookup(found)) return; + usedLng = code; + var finalKeys = [key]; -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; + if (_this4.i18nFormat && _this4.i18nFormat.addLookupKeys) { + _this4.i18nFormat.addLookupKeys(finalKeys, key, code, ns, options); + } else { + var pluralSuffix; + if (needsPluralHandling) pluralSuffix = _this4.pluralResolver.getSuffix(code, options.count, options); + var zeroSuffix = '_zero'; - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; + if (needsPluralHandling) { + finalKeys.push(key + pluralSuffix); -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} + if (needsZeroSuffixLookup) { + finalKeys.push(key + zeroSuffix); + } + } -var kCustomPromisifiedSymbol = typeof Symbol !== 'undefined' ? Symbol('util.promisify.custom') : undefined; + if (needsContextHandling) { + var contextKey = "".concat(key).concat(_this4.options.contextSeparator).concat(options.context); + finalKeys.push(contextKey); -exports.promisify = function promisify(original) { - if (typeof original !== 'function') - throw new TypeError('The "original" argument must be of type Function'); + if (needsPluralHandling) { + finalKeys.push(contextKey + pluralSuffix); - if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) { - var fn = original[kCustomPromisifiedSymbol]; - if (typeof fn !== 'function') { - throw new TypeError('The "util.promisify.custom" argument must be of type Function'); - } - Object.defineProperty(fn, kCustomPromisifiedSymbol, { - value: fn, enumerable: false, writable: false, configurable: true - }); - return fn; - } + if (needsZeroSuffixLookup) { + finalKeys.push(contextKey + zeroSuffix); + } + } + } + } - function fn() { - var promiseResolve, promiseReject; - var promise = new Promise(function (resolve, reject) { - promiseResolve = resolve; - promiseReject = reject; - }); + var possibleKey; - var args = []; - for (var i = 0; i < arguments.length; i++) { - args.push(arguments[i]); + while (possibleKey = finalKeys.pop()) { + if (!_this4.isValidLookup(found)) { + exactUsedKey = possibleKey; + found = _this4.getResource(code, ns, possibleKey, options); + } + } + }); + }); + }); + return { + res: found, + usedKey: usedKey, + exactUsedKey: exactUsedKey, + usedLng: usedLng, + usedNS: usedNS + }; } - args.push(function (err, value) { - if (err) { - promiseReject(err); - } else { - promiseResolve(value); + }, { + key: "isValidLookup", + value: function isValidLookup(res) { + return res !== undefined && !(!this.options.returnNull && res === null) && !(!this.options.returnEmptyString && res === ''); + } + }, { + key: "getResource", + value: function getResource(code, ns, key) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + if (this.i18nFormat && this.i18nFormat.getResource) return this.i18nFormat.getResource(code, ns, key, options); + return this.resourceStore.getResource(code, ns, key, options); + } + }], [{ + key: "hasDefaultValue", + value: function hasDefaultValue(options) { + var prefix = 'defaultValue'; + + for (var option in options) { + if (Object.prototype.hasOwnProperty.call(options, option) && prefix === option.substring(0, prefix.length) && undefined !== options[option]) { + return true; + } } - }); - try { - original.apply(this, args); - } catch (err) { - promiseReject(err); + return false; } + }]); - return promise; - } - - Object.setPrototypeOf(fn, Object.getPrototypeOf(original)); + return Translator; +}(EventEmitter); - if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, { - value: fn, enumerable: false, writable: false, configurable: true - }); - return Object.defineProperties( - fn, - getOwnPropertyDescriptors(original) - ); +function capitalize(string) { + return string.charAt(0).toUpperCase() + string.slice(1); } -exports.promisify.custom = kCustomPromisifiedSymbol - -function callbackifyOnRejected(reason, cb) { - // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M). - // Because `null` is a special error value in callbacks which means "no error - // occurred", we error-wrap so the callback consumer can distinguish between - // "the promise rejected with null" or "the promise fulfilled with undefined". - if (!reason) { - var newReason = new Error('Promise was rejected with a falsy value'); - newReason.reason = reason; - reason = newReason; - } - return cb(reason); -} +var LanguageUtil = function () { + function LanguageUtil(options) { + _classCallCheck__default['default'](this, LanguageUtil); -function callbackify(original) { - if (typeof original !== 'function') { - throw new TypeError('The "original" argument must be of type Function'); + this.options = options; + this.supportedLngs = this.options.supportedLngs || false; + this.logger = baseLogger.create('languageUtils'); } - // We DO NOT return the promise as it gives the user a false sense that - // the promise is actually somehow related to the callback's execution - // and that the callback throwing will reject the promise. - function callbackified() { - var args = []; - for (var i = 0; i < arguments.length; i++) { - args.push(arguments[i]); + _createClass__default['default'](LanguageUtil, [{ + key: "getScriptPartFromCode", + value: function getScriptPartFromCode(code) { + if (!code || code.indexOf('-') < 0) return null; + var p = code.split('-'); + if (p.length === 2) return null; + p.pop(); + if (p[p.length - 1].toLowerCase() === 'x') return null; + return this.formatLanguageCode(p.join('-')); } - - var maybeCb = args.pop(); - if (typeof maybeCb !== 'function') { - throw new TypeError('The last argument must be of type Function'); + }, { + key: "getLanguagePartFromCode", + value: function getLanguagePartFromCode(code) { + if (!code || code.indexOf('-') < 0) return code; + var p = code.split('-'); + return this.formatLanguageCode(p[0]); } - var self = this; - var cb = function() { - return maybeCb.apply(self, arguments); - }; - // In true node style we process the callback on `nextTick` with all the - // implications (stack, `uncaughtException`, `async_hooks`) - original.apply(this, args) - .then(function(ret) { process.nextTick(cb, null, ret) }, - function(rej) { process.nextTick(callbackifyOnRejected, rej, cb) }); - } - - Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original)); - Object.defineProperties(callbackified, - getOwnPropertyDescriptors(original)); - return callbackified; -} -exports.callbackify = callbackify; + }, { + key: "formatLanguageCode", + value: function formatLanguageCode(code) { + if (typeof code === 'string' && code.indexOf('-') > -1) { + var specialCases = ['hans', 'hant', 'latn', 'cyrl', 'cans', 'mong', 'arab']; + var p = code.split('-'); -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../../process/browser.js */ "./node_modules/process/browser.js"))) + if (this.options.lowerCaseLng) { + p = p.map(function (part) { + return part.toLowerCase(); + }); + } else if (p.length === 2) { + p[0] = p[0].toLowerCase(); + p[1] = p[1].toUpperCase(); + if (specialCases.indexOf(p[1].toLowerCase()) > -1) p[1] = capitalize(p[1].toLowerCase()); + } else if (p.length === 3) { + p[0] = p[0].toLowerCase(); + if (p[1].length === 2) p[1] = p[1].toUpperCase(); + if (p[0] !== 'sgn' && p[2].length === 2) p[2] = p[2].toUpperCase(); + if (specialCases.indexOf(p[1].toLowerCase()) > -1) p[1] = capitalize(p[1].toLowerCase()); + if (specialCases.indexOf(p[2].toLowerCase()) > -1) p[2] = capitalize(p[2].toLowerCase()); + } -/***/ }), + return p.join('-'); + } -/***/ "./node_modules/webpack-stream/node_modules/webpack/buildin/global.js": -/*!***********************************!*\ - !*** (webpack)/buildin/global.js ***! - \***********************************/ -/*! no static exports found */ -/***/ (function(module, exports) { + return this.options.cleanCode || this.options.lowerCaseLng ? code.toLowerCase() : code; + } + }, { + key: "isSupportedCode", + value: function isSupportedCode(code) { + if (this.options.load === 'languageOnly' || this.options.nonExplicitSupportedLngs) { + code = this.getLanguagePartFromCode(code); + } -var g; + return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.indexOf(code) > -1; + } + }, { + key: "getBestMatchFromCodes", + value: function getBestMatchFromCodes(codes) { + var _this = this; -// This works in non-strict mode -g = (function() { - return this; -})(); + if (!codes) return null; + var found; + codes.forEach(function (code) { + if (found) return; -try { - // This works if eval is allowed (see CSP) - g = g || new Function("return this")(); -} catch (e) { - // This works if the window reference is available - if (typeof window === "object") g = window; -} + var cleanedLng = _this.formatLanguageCode(code); -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} + if (!_this.options.supportedLngs || _this.isSupportedCode(cleanedLng)) found = cleanedLng; + }); -module.exports = g; + if (!found && this.options.supportedLngs) { + codes.forEach(function (code) { + if (found) return; + var lngOnly = _this.getLanguagePartFromCode(code); -/***/ }), + if (_this.isSupportedCode(lngOnly)) return found = lngOnly; + found = _this.options.supportedLngs.find(function (supportedLng) { + if (supportedLng.indexOf(lngOnly) === 0) return supportedLng; + }); + }); + } -/***/ "./src/extractors/chroma.js": -/*!**********************************!*\ - !*** ./src/extractors/chroma.js ***! - \**********************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (!found) found = this.getFallbackCodes(this.options.fallbackLng)[0]; + return found; + } + }, { + key: "getFallbackCodes", + value: function getFallbackCodes(fallbacks, code) { + if (!fallbacks) return []; + if (typeof fallbacks === 'function') fallbacks = fallbacks(code); + if (typeof fallbacks === 'string') fallbacks = [fallbacks]; + if (Object.prototype.toString.apply(fallbacks) === '[object Array]') return fallbacks; + if (!code) return fallbacks["default"] || []; + var found = fallbacks[code]; + if (!found) found = fallbacks[this.getScriptPartFromCode(code)]; + if (!found) found = fallbacks[this.formatLanguageCode(code)]; + if (!found) found = fallbacks[this.getLanguagePartFromCode(code)]; + if (!found) found = fallbacks["default"]; + return found || []; + } + }, { + key: "toResolveHierarchy", + value: function toResolveHierarchy(code, fallbackCode) { + var _this2 = this; -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } + var fallbackCodes = this.getFallbackCodes(fallbackCode || this.options.fallbackLng || [], code); + var codes = []; -function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } + var addCode = function addCode(c) { + if (!c) return; -function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } + if (_this2.isSupportedCode(c)) { + codes.push(c); + } else { + _this2.logger.warn("rejecting language code not found in supportedLngs: ".concat(c)); + } + }; -function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } + if (typeof code === 'string' && code.indexOf('-') > -1) { + if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code)); + if (this.options.load !== 'languageOnly' && this.options.load !== 'currentOnly') addCode(this.getScriptPartFromCode(code)); + if (this.options.load !== 'currentOnly') addCode(this.getLanguagePartFromCode(code)); + } else if (typeof code === 'string') { + addCode(this.formatLanguageCode(code)); + } -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + fallbackCodes.forEach(function (fc) { + if (codes.indexOf(fc) < 0) addCode(_this2.formatLanguageCode(fc)); + }); + return codes; + } + }]); -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.ampSpectrum) !== 'object') { - throw new TypeError('Valid ampSpectrum is required to generate chroma'); - } + return LanguageUtil; +}(); - if (_typeof(args.chromaFilterBank) !== 'object') { - throw new TypeError('Valid chromaFilterBank is required to generate chroma'); +var sets = [{ + lngs: ['ach', 'ak', 'am', 'arn', 'br', 'fil', 'gun', 'ln', 'mfe', 'mg', 'mi', 'oc', 'pt', 'pt-BR', 'tg', 'tl', 'ti', 'tr', 'uz', 'wa'], + nr: [1, 2], + fc: 1 +}, { + lngs: ['af', 'an', 'ast', 'az', 'bg', 'bn', 'ca', 'da', 'de', 'dev', 'el', 'en', 'eo', 'es', 'et', 'eu', 'fi', 'fo', 'fur', 'fy', 'gl', 'gu', 'ha', 'hi', 'hu', 'hy', 'ia', 'it', 'kk', 'kn', 'ku', 'lb', 'mai', 'ml', 'mn', 'mr', 'nah', 'nap', 'nb', 'ne', 'nl', 'nn', 'no', 'nso', 'pa', 'pap', 'pms', 'ps', 'pt-PT', 'rm', 'sco', 'se', 'si', 'so', 'son', 'sq', 'sv', 'sw', 'ta', 'te', 'tk', 'ur', 'yo'], + nr: [1, 2], + fc: 2 +}, { + lngs: ['ay', 'bo', 'cgg', 'fa', 'ht', 'id', 'ja', 'jbo', 'ka', 'km', 'ko', 'ky', 'lo', 'ms', 'sah', 'su', 'th', 'tt', 'ug', 'vi', 'wo', 'zh'], + nr: [1], + fc: 3 +}, { + lngs: ['be', 'bs', 'cnr', 'dz', 'hr', 'ru', 'sr', 'uk'], + nr: [1, 2, 5], + fc: 4 +}, { + lngs: ['ar'], + nr: [0, 1, 2, 3, 11, 100], + fc: 5 +}, { + lngs: ['cs', 'sk'], + nr: [1, 2, 5], + fc: 6 +}, { + lngs: ['csb', 'pl'], + nr: [1, 2, 5], + fc: 7 +}, { + lngs: ['cy'], + nr: [1, 2, 3, 8], + fc: 8 +}, { + lngs: ['fr'], + nr: [1, 2], + fc: 9 +}, { + lngs: ['ga'], + nr: [1, 2, 3, 7, 11], + fc: 10 +}, { + lngs: ['gd'], + nr: [1, 2, 3, 20], + fc: 11 +}, { + lngs: ['is'], + nr: [1, 2], + fc: 12 +}, { + lngs: ['jv'], + nr: [0, 1], + fc: 13 +}, { + lngs: ['kw'], + nr: [1, 2, 3, 4], + fc: 14 +}, { + lngs: ['lt'], + nr: [1, 2, 10], + fc: 15 +}, { + lngs: ['lv'], + nr: [1, 2, 0], + fc: 16 +}, { + lngs: ['mk'], + nr: [1, 2], + fc: 17 +}, { + lngs: ['mnk'], + nr: [0, 1, 2], + fc: 18 +}, { + lngs: ['mt'], + nr: [1, 2, 11, 20], + fc: 19 +}, { + lngs: ['or'], + nr: [2, 1], + fc: 2 +}, { + lngs: ['ro'], + nr: [1, 2, 20], + fc: 20 +}, { + lngs: ['sl'], + nr: [5, 1, 2, 3], + fc: 21 +}, { + lngs: ['he', 'iw'], + nr: [1, 2, 20, 21], + fc: 22 +}]; +var _rulesPluralsTypes = { + 1: function _(n) { + return Number(n > 1); + }, + 2: function _(n) { + return Number(n != 1); + }, + 3: function _(n) { + return 0; + }, + 4: function _(n) { + return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); + }, + 5: function _(n) { + return Number(n == 0 ? 0 : n == 1 ? 1 : n == 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5); + }, + 6: function _(n) { + return Number(n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2); + }, + 7: function _(n) { + return Number(n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); + }, + 8: function _(n) { + return Number(n == 1 ? 0 : n == 2 ? 1 : n != 8 && n != 11 ? 2 : 3); + }, + 9: function _(n) { + return Number(n >= 2); + }, + 10: function _(n) { + return Number(n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4); + }, + 11: function _(n) { + return Number(n == 1 || n == 11 ? 0 : n == 2 || n == 12 ? 1 : n > 2 && n < 20 ? 2 : 3); + }, + 12: function _(n) { + return Number(n % 10 != 1 || n % 100 == 11); + }, + 13: function _(n) { + return Number(n !== 0); + }, + 14: function _(n) { + return Number(n == 1 ? 0 : n == 2 ? 1 : n == 3 ? 2 : 3); + }, + 15: function _(n) { + return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); + }, + 16: function _(n) { + return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n !== 0 ? 1 : 2); + }, + 17: function _(n) { + return Number(n == 1 || n % 10 == 1 && n % 100 != 11 ? 0 : 1); + }, + 18: function _(n) { + return Number(n == 0 ? 0 : n == 1 ? 1 : 2); + }, + 19: function _(n) { + return Number(n == 1 ? 0 : n == 0 || n % 100 > 1 && n % 100 < 11 ? 1 : n % 100 > 10 && n % 100 < 20 ? 2 : 3); + }, + 20: function _(n) { + return Number(n == 1 ? 0 : n == 0 || n % 100 > 0 && n % 100 < 20 ? 1 : 2); + }, + 21: function _(n) { + return Number(n % 100 == 1 ? 1 : n % 100 == 2 ? 2 : n % 100 == 3 || n % 100 == 4 ? 3 : 0); + }, + 22: function _(n) { + return Number(n == 1 ? 0 : n == 2 ? 1 : (n < 0 || n > 10) && n % 10 == 0 ? 2 : 3); } +}; +var deprecatedJsonVersions = ['v1', 'v2', 'v3']; +var suffixesOrder = { + zero: 0, + one: 1, + two: 2, + few: 3, + many: 4, + other: 5 +}; - var chromagram = args.chromaFilterBank.map(function (row, i) { - return args.ampSpectrum.reduce(function (acc, v, j) { - return acc + v * row[j]; - }, 0); +function createRules() { + var rules = {}; + sets.forEach(function (set) { + set.lngs.forEach(function (l) { + rules[l] = { + numbers: set.nr, + plurals: _rulesPluralsTypes[set.fc] + }; + }); }); - var maxVal = Math.max.apply(Math, _toConsumableArray(chromagram)); - return maxVal ? chromagram.map(function (v) { - return v / maxVal; - }) : chromagram; -}); - -/***/ }), - -/***/ "./src/extractors/energy.js": -/*!**********************************!*\ - !*** ./src/extractors/energy.js ***! - \**********************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + return rules; +} -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! assert */ "./node_modules/assert/assert.js"); -/* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(assert__WEBPACK_IMPORTED_MODULE_0__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } +var PluralResolver = function () { + function PluralResolver(languageUtils) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + _classCallCheck__default['default'](this, PluralResolver); -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].signal) !== 'object') { - throw new TypeError(); - } + this.languageUtils = languageUtils; + this.options = options; + this.logger = baseLogger.create('pluralResolver'); - var energy = 0; + if ((!this.options.compatibilityJSON || this.options.compatibilityJSON === 'v4') && (typeof Intl === 'undefined' || !Intl.PluralRules)) { + this.options.compatibilityJSON = 'v3'; + this.logger.error('Your environment seems not to be Intl API compatible, use an Intl.PluralRules polyfill. Will fallback to the compatibilityJSON v3 format handling.'); + } - for (var i = 0; i < arguments[0].signal.length; i++) { - energy += Math.pow(Math.abs(arguments[0].signal[i]), 2); + this.rules = createRules(); } - return energy; -}); - -/***/ }), - -/***/ "./src/extractors/extractorUtilities.js": -/*!**********************************************!*\ - !*** ./src/extractors/extractorUtilities.js ***! - \**********************************************/ -/*! exports provided: mu */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mu", function() { return mu; }); -function mu(i, amplitudeSpect) { - var numerator = 0; - var denominator = 0; + _createClass__default['default'](PluralResolver, [{ + key: "addRule", + value: function addRule(lng, obj) { + this.rules[lng] = obj; + } + }, { + key: "getRule", + value: function getRule(code) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - for (var k = 0; k < amplitudeSpect.length; k++) { - numerator += Math.pow(k, i) * Math.abs(amplitudeSpect[k]); - denominator += amplitudeSpect[k]; - } + if (this.shouldUseIntlApi()) { + try { + return new Intl.PluralRules(code, { + type: options.ordinal ? 'ordinal' : 'cardinal' + }); + } catch (_unused) { + return; + } + } - return numerator / denominator; -} + return this.rules[code] || this.rules[this.languageUtils.getLanguagePartFromCode(code)]; + } + }, { + key: "needsPlural", + value: function needsPlural(code) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var rule = this.getRule(code, options); -/***/ }), + if (this.shouldUseIntlApi()) { + return rule && rule.resolvedOptions().pluralCategories.length > 1; + } -/***/ "./src/extractors/loudness.js": -/*!************************************!*\ - !*** ./src/extractors/loudness.js ***! - \************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + return rule && rule.numbers.length > 1; + } + }, { + key: "getPluralFormsOfKey", + value: function getPluralFormsOfKey(code, key) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + return this.getSuffixes(code, options).map(function (suffix) { + return "".concat(key).concat(suffix); + }); + } + }, { + key: "getSuffixes", + value: function getSuffixes(code) { + var _this = this; -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var rule = this.getRule(code, options); -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.ampSpectrum) !== 'object' || _typeof(args.barkScale) !== 'object') { - throw new TypeError(); - } + if (!rule) { + return []; + } - var NUM_BARK_BANDS = 24; - var specific = new Float32Array(NUM_BARK_BANDS); - var total = 0; - var normalisedSpectrum = args.ampSpectrum; - var bbLimits = new Int32Array(NUM_BARK_BANDS + 1); - bbLimits[0] = 0; - var currentBandEnd = args.barkScale[normalisedSpectrum.length - 1] / NUM_BARK_BANDS; - var currentBand = 1; + if (this.shouldUseIntlApi()) { + return rule.resolvedOptions().pluralCategories.sort(function (pluralCategory1, pluralCategory2) { + return suffixesOrder[pluralCategory1] - suffixesOrder[pluralCategory2]; + }).map(function (pluralCategory) { + return "".concat(_this.options.prepend).concat(pluralCategory); + }); + } - for (var i = 0; i < normalisedSpectrum.length; i++) { - while (args.barkScale[i] > currentBandEnd) { - bbLimits[currentBand++] = i; - currentBandEnd = currentBand * args.barkScale[normalisedSpectrum.length - 1] / NUM_BARK_BANDS; + return rule.numbers.map(function (number) { + return _this.getSuffix(code, number, options); + }); } - } + }, { + key: "getSuffix", + value: function getSuffix(code, count) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + var rule = this.getRule(code, options); - bbLimits[NUM_BARK_BANDS] = normalisedSpectrum.length - 1; //process + if (rule) { + if (this.shouldUseIntlApi()) { + return "".concat(this.options.prepend).concat(rule.select(count)); + } - for (var _i = 0; _i < NUM_BARK_BANDS; _i++) { - var sum = 0; + return this.getSuffixRetroCompatible(rule, count); + } - for (var j = bbLimits[_i]; j < bbLimits[_i + 1]; j++) { - sum += normalisedSpectrum[j]; + this.logger.warn("no plural rule found for: ".concat(code)); + return ''; } + }, { + key: "getSuffixRetroCompatible", + value: function getSuffixRetroCompatible(rule, count) { + var _this2 = this; - specific[_i] = Math.pow(sum, 0.23); - } //get total loudness - - - for (var _i2 = 0; _i2 < specific.length; _i2++) { - total += specific[_i2]; - } - - return { - specific: specific, - total: total - }; -}); - -/***/ }), + var idx = rule.noAbs ? rule.plurals(count) : rule.plurals(Math.abs(count)); + var suffix = rule.numbers[idx]; -/***/ "./src/extractors/mfcc.js": -/*!********************************!*\ - !*** ./src/extractors/mfcc.js ***! - \********************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) { + if (suffix === 2) { + suffix = 'plural'; + } else if (suffix === 1) { + suffix = ''; + } + } -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _powerSpectrum__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./powerSpectrum */ "./src/extractors/powerSpectrum.js"); -/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./../utilities */ "./src/utilities.js"); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + var returnSuffix = function returnSuffix() { + return _this2.options.prepend && suffix.toString() ? _this2.options.prepend + suffix.toString() : suffix.toString(); + }; + if (this.options.compatibilityJSON === 'v1') { + if (suffix === 1) return ''; + if (typeof suffix === 'number') return "_plural_".concat(suffix.toString()); + return returnSuffix(); + } else if (this.options.compatibilityJSON === 'v2') { + return returnSuffix(); + } else if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) { + return returnSuffix(); + } + return this.options.prepend && idx.toString() ? this.options.prepend + idx.toString() : idx.toString(); + } + }, { + key: "shouldUseIntlApi", + value: function shouldUseIntlApi() { + return !deprecatedJsonVersions.includes(this.options.compatibilityJSON); + } + }]); + return PluralResolver; +}(); +function ownKeys$3(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } -var dct = __webpack_require__(/*! dct */ "./node_modules/dct/index.js"); +function _objectSpread$3(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$3(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$3(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.ampSpectrum) !== 'object') { - throw new TypeError('Valid ampSpectrum is required to generate MFCC'); - } +var Interpolator = function () { + function Interpolator() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - if (_typeof(args.melFilterBank) !== 'object') { - throw new TypeError('Valid melFilterBank is required to generate MFCC'); - } + _classCallCheck__default['default'](this, Interpolator); - var numberOfMFCCCoefficients = Math.min(40, Math.max(1, args.numberOfMFCCCoefficients || 13)); // Tutorial from: - // http://practicalcryptography.com/miscellaneous/machine-learning - // /guide-mel-frequency-cepstral-coefficients-mfccs/ + this.logger = baseLogger.create('interpolator'); + this.options = options; - var powSpec = Object(_powerSpectrum__WEBPACK_IMPORTED_MODULE_0__["default"])(args); - var numFilters = args.melFilterBank.length; - var filtered = Array(numFilters); + this.format = options.interpolation && options.interpolation.format || function (value) { + return value; + }; - if (numFilters < numberOfMFCCCoefficients) { - throw new Error("Insufficient filter bank for requested number of coefficients"); + this.init(options); } - var loggedMelBands = new Float32Array(numFilters); - - for (var i = 0; i < loggedMelBands.length; i++) { - filtered[i] = new Float32Array(args.bufferSize / 2); - loggedMelBands[i] = 0; - - for (var j = 0; j < args.bufferSize / 2; j++) { - //point-wise multiplication between power spectrum and filterbanks. - filtered[i][j] = args.melFilterBank[i][j] * powSpec[j]; //summing up all of the coefficients into one array - - loggedMelBands[i] += filtered[i][j]; - } //log each coefficient. - - - loggedMelBands[i] = Math.log(loggedMelBands[i] + 1); - } //dct - - - var loggedMelBandsArray = Array.prototype.slice.call(loggedMelBands); - var mfccs = dct(loggedMelBandsArray).slice(0, numberOfMFCCCoefficients); - return mfccs; -}); - -/***/ }), - -/***/ "./src/extractors/perceptualSharpness.js": -/*!***********************************************!*\ - !*** ./src/extractors/perceptualSharpness.js ***! - \***********************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _loudness__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./loudness */ "./src/extractors/loudness.js"); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + _createClass__default['default'](Interpolator, [{ + key: "init", + value: function init() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + if (!options.interpolation) options.interpolation = { + escapeValue: true + }; + var iOpts = options.interpolation; + this.escape = iOpts.escape !== undefined ? iOpts.escape : escape; + this.escapeValue = iOpts.escapeValue !== undefined ? iOpts.escapeValue : true; + this.useRawValueToEscape = iOpts.useRawValueToEscape !== undefined ? iOpts.useRawValueToEscape : false; + this.prefix = iOpts.prefix ? regexEscape(iOpts.prefix) : iOpts.prefixEscaped || '{{'; + this.suffix = iOpts.suffix ? regexEscape(iOpts.suffix) : iOpts.suffixEscaped || '}}'; + this.formatSeparator = iOpts.formatSeparator ? iOpts.formatSeparator : iOpts.formatSeparator || ','; + this.unescapePrefix = iOpts.unescapeSuffix ? '' : iOpts.unescapePrefix || '-'; + this.unescapeSuffix = this.unescapePrefix ? '' : iOpts.unescapeSuffix || ''; + this.nestingPrefix = iOpts.nestingPrefix ? regexEscape(iOpts.nestingPrefix) : iOpts.nestingPrefixEscaped || regexEscape('$t('); + this.nestingSuffix = iOpts.nestingSuffix ? regexEscape(iOpts.nestingSuffix) : iOpts.nestingSuffixEscaped || regexEscape(')'); + this.nestingOptionsSeparator = iOpts.nestingOptionsSeparator ? iOpts.nestingOptionsSeparator : iOpts.nestingOptionsSeparator || ','; + this.maxReplaces = iOpts.maxReplaces ? iOpts.maxReplaces : 1000; + this.alwaysFormat = iOpts.alwaysFormat !== undefined ? iOpts.alwaysFormat : false; + this.resetRegExp(); + } + }, { + key: "reset", + value: function reset() { + if (this.options) this.init(this.options); + } + }, { + key: "resetRegExp", + value: function resetRegExp() { + var regexpStr = "".concat(this.prefix, "(.+?)").concat(this.suffix); + this.regexp = new RegExp(regexpStr, 'g'); + var regexpUnescapeStr = "".concat(this.prefix).concat(this.unescapePrefix, "(.+?)").concat(this.unescapeSuffix).concat(this.suffix); + this.regexpUnescape = new RegExp(regexpUnescapeStr, 'g'); + var nestingRegexpStr = "".concat(this.nestingPrefix, "(.+?)").concat(this.nestingSuffix); + this.nestingRegexp = new RegExp(nestingRegexpStr, 'g'); + } + }, { + key: "interpolate", + value: function interpolate(str, data, lng, options) { + var _this = this; + var match; + var value; + var replaces; + var defaultData = this.options && this.options.interpolation && this.options.interpolation.defaultVariables || {}; -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].signal) !== 'object') { - throw new TypeError(); - } + function regexSafe(val) { + return val.replace(/\$/g, '$$$$'); + } - var loudnessValue = Object(_loudness__WEBPACK_IMPORTED_MODULE_0__["default"])(arguments[0]); - var spec = loudnessValue.specific; - var output = 0; + var handleFormat = function handleFormat(key) { + if (key.indexOf(_this.formatSeparator) < 0) { + var path = getPathWithDefaults(data, defaultData, key); + return _this.alwaysFormat ? _this.format(path, undefined, lng, _objectSpread$3(_objectSpread$3(_objectSpread$3({}, options), data), {}, { + interpolationkey: key + })) : path; + } - for (var i = 0; i < spec.length; i++) { - if (i < 15) { - output += (i + 1) * spec[i + 1]; - } else { - output += 0.066 * Math.exp(0.171 * (i + 1)); - } - } + var p = key.split(_this.formatSeparator); + var k = p.shift().trim(); + var f = p.join(_this.formatSeparator).trim(); + return _this.format(getPathWithDefaults(data, defaultData, k), f, lng, _objectSpread$3(_objectSpread$3(_objectSpread$3({}, options), data), {}, { + interpolationkey: k + })); + }; - output *= 0.11 / loudnessValue.total; - return output; -}); + this.resetRegExp(); + var missingInterpolationHandler = options && options.missingInterpolationHandler || this.options.missingInterpolationHandler; + var skipOnVariables = options && options.interpolation && options.interpolation.skipOnVariables || this.options.interpolation.skipOnVariables; + var todos = [{ + regex: this.regexpUnescape, + safeValue: function safeValue(val) { + return regexSafe(val); + } + }, { + regex: this.regexp, + safeValue: function safeValue(val) { + return _this.escapeValue ? regexSafe(_this.escape(val)) : regexSafe(val); + } + }]; + todos.forEach(function (todo) { + replaces = 0; -/***/ }), + while (match = todo.regex.exec(str)) { + value = handleFormat(match[1].trim()); -/***/ "./src/extractors/perceptualSpread.js": -/*!********************************************!*\ - !*** ./src/extractors/perceptualSpread.js ***! - \********************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (value === undefined) { + if (typeof missingInterpolationHandler === 'function') { + var temp = missingInterpolationHandler(str, match, options); + value = typeof temp === 'string' ? temp : ''; + } else if (skipOnVariables) { + value = match[0]; + continue; + } else { + _this.logger.warn("missed to pass in variable ".concat(match[1], " for interpolating ").concat(str)); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _loudness__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./loudness */ "./src/extractors/loudness.js"); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + value = ''; + } + } else if (typeof value !== 'string' && !_this.useRawValueToEscape) { + value = makeString(value); + } + var safeValue = todo.safeValue(value); + str = str.replace(match[0], safeValue); -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].signal) !== 'object') { - throw new TypeError(); - } + if (skipOnVariables) { + todo.regex.lastIndex += safeValue.length; + todo.regex.lastIndex -= match[0].length; + } else { + todo.regex.lastIndex = 0; + } - var loudnessValue = Object(_loudness__WEBPACK_IMPORTED_MODULE_0__["default"])(arguments[0]); - var max = 0; + replaces++; - for (var i = 0; i < loudnessValue.specific.length; i++) { - if (loudnessValue.specific[i] > max) { - max = loudnessValue.specific[i]; + if (replaces >= _this.maxReplaces) { + break; + } + } + }); + return str; } - } + }, { + key: "nest", + value: function nest(str, fc) { + var _this2 = this; - var spread = Math.pow((loudnessValue.total - max) / loudnessValue.total, 2); - return spread; -}); + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + var match; + var value; -/***/ }), + var clonedOptions = _objectSpread$3({}, options); -/***/ "./src/extractors/powerSpectrum.js": -/*!*****************************************!*\ - !*** ./src/extractors/powerSpectrum.js ***! - \*****************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + clonedOptions.applyPostProcessor = false; + delete clonedOptions.defaultValue; -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + function handleHasOptions(key, inheritedOptions) { + var sep = this.nestingOptionsSeparator; + if (key.indexOf(sep) < 0) return key; + var c = key.split(new RegExp("".concat(sep, "[ ]*{"))); + var optionsString = "{".concat(c[1]); + key = c[0]; + optionsString = this.interpolate(optionsString, clonedOptions); + optionsString = optionsString.replace(/'/g, '"'); -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].ampSpectrum) !== 'object') { - throw new TypeError(); - } + try { + clonedOptions = JSON.parse(optionsString); + if (inheritedOptions) clonedOptions = _objectSpread$3(_objectSpread$3({}, inheritedOptions), clonedOptions); + } catch (e) { + this.logger.warn("failed parsing options string in nesting for key ".concat(key), e); + return "".concat(key).concat(sep).concat(optionsString); + } - var powerSpectrum = new Float32Array(arguments[0].ampSpectrum.length); + delete clonedOptions.defaultValue; + return key; + } - for (var i = 0; i < powerSpectrum.length; i++) { - powerSpectrum[i] = Math.pow(arguments[0].ampSpectrum[i], 2); - } + while (match = this.nestingRegexp.exec(str)) { + var formatters = []; + var doReduce = false; - return powerSpectrum; -}); + if (match[0].indexOf(this.formatSeparator) !== -1 && !/{.*}/.test(match[1])) { + var r = match[1].split(this.formatSeparator).map(function (elem) { + return elem.trim(); + }); + match[1] = r.shift(); + formatters = r; + doReduce = true; + } -/***/ }), + value = fc(handleHasOptions.call(this, match[1].trim(), clonedOptions), clonedOptions); + if (value && match[0] === str && typeof value !== 'string') return value; + if (typeof value !== 'string') value = makeString(value); -/***/ "./src/extractors/rms.js": -/*!*******************************!*\ - !*** ./src/extractors/rms.js ***! - \*******************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (!value) { + this.logger.warn("missed to resolve ".concat(match[1], " for nesting ").concat(str)); + value = ''; + } -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + if (doReduce) { + value = formatters.reduce(function (v, f) { + return _this2.format(v, f, options.lng, _objectSpread$3(_objectSpread$3({}, options), {}, { + interpolationkey: match[1].trim() + })); + }, value.trim()); + } -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.signal) !== 'object') { - throw new TypeError(); - } + str = str.replace(match[0], value); + this.regexp.lastIndex = 0; + } - var rms = 0; + return str; + } + }]); - for (var i = 0; i < args.signal.length; i++) { - rms += Math.pow(args.signal[i], 2); - } + return Interpolator; +}(); - rms = rms / args.signal.length; - rms = Math.sqrt(rms); - return rms; -}); +function ownKeys$4(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } -/***/ }), +function _objectSpread$4(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$4(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$4(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } -/***/ "./src/extractors/spectralCentroid.js": -/*!********************************************!*\ - !*** ./src/extractors/spectralCentroid.js ***! - \********************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +function parseFormatStr(formatStr) { + var formatName = formatStr.toLowerCase().trim(); + var formatOptions = {}; -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + if (formatStr.indexOf('(') > -1) { + var p = formatStr.split('('); + formatName = p[0].toLowerCase().trim(); + var optStr = p[1].substring(0, p[1].length - 1); + if (formatName === 'currency' && optStr.indexOf(':') < 0) { + if (!formatOptions.currency) formatOptions.currency = optStr.trim(); + } else if (formatName === 'relativetime' && optStr.indexOf(':') < 0) { + if (!formatOptions.range) formatOptions.range = optStr.trim(); + } else { + var opts = optStr.split(';'); + opts.forEach(function (opt) { + if (!opt) return; -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].ampSpectrum) !== 'object') { - throw new TypeError(); - } + var _opt$split = opt.split(':'), + _opt$split2 = _toArray__default['default'](_opt$split), + key = _opt$split2[0], + rest = _opt$split2.slice(1); - return Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, arguments[0].ampSpectrum); -}); + var val = rest.join(':'); + if (val.trim() === 'false') formatOptions[key.trim()] = false; + if (val.trim() === 'true') formatOptions[key.trim()] = true; + if (!isNaN(val.trim())) formatOptions[key.trim()] = parseInt(val.trim(), 10); + if (!formatOptions[key.trim()]) formatOptions[key.trim()] = val.trim(); + }); + } + } -/***/ }), + return { + formatName: formatName, + formatOptions: formatOptions + }; +} -/***/ "./src/extractors/spectralFlatness.js": -/*!********************************************!*\ - !*** ./src/extractors/spectralFlatness.js ***! - \********************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +var Formatter = function () { + function Formatter() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + _classCallCheck__default['default'](this, Formatter); -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].ampSpectrum) !== 'object') { - throw new TypeError(); + this.logger = baseLogger.create('formatter'); + this.options = options; + this.formats = { + number: function number(val, lng, options) { + return new Intl.NumberFormat(lng, options).format(val); + }, + currency: function currency(val, lng, options) { + return new Intl.NumberFormat(lng, _objectSpread$4(_objectSpread$4({}, options), {}, { + style: 'currency' + })).format(val); + }, + datetime: function datetime(val, lng, options) { + return new Intl.DateTimeFormat(lng, _objectSpread$4({}, options)).format(val); + }, + relativetime: function relativetime(val, lng, options) { + return new Intl.RelativeTimeFormat(lng, _objectSpread$4({}, options)).format(val, options.range || 'day'); + }, + list: function list(val, lng, options) { + return new Intl.ListFormat(lng, _objectSpread$4({}, options)).format(val); + } + }; + this.init(options); } - var numerator = 0; - var denominator = 0; - - for (var i = 0; i < arguments[0].ampSpectrum.length; i++) { - numerator += Math.log(arguments[0].ampSpectrum[i]); - denominator += arguments[0].ampSpectrum[i]; - } + _createClass__default['default'](Formatter, [{ + key: "init", + value: function init(services) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + interpolation: {} + }; + var iOpts = options.interpolation; + this.formatSeparator = iOpts.formatSeparator ? iOpts.formatSeparator : iOpts.formatSeparator || ','; + } + }, { + key: "add", + value: function add(name, fc) { + this.formats[name] = fc; + } + }, { + key: "format", + value: function format(value, _format, lng, options) { + var _this = this; - return Math.exp(numerator / arguments[0].ampSpectrum.length) * arguments[0].ampSpectrum.length / denominator; -}); + var formats = _format.split(this.formatSeparator); -/***/ }), + var result = formats.reduce(function (mem, f) { + var _parseFormatStr = parseFormatStr(f), + formatName = _parseFormatStr.formatName, + formatOptions = _parseFormatStr.formatOptions; -/***/ "./src/extractors/spectralFlux.js": -/*!****************************************!*\ - !*** ./src/extractors/spectralFlux.js ***! - \****************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (_this.formats[formatName]) { + var formatted = mem; -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + try { + var valOptions = options && options.formatParams && options.formatParams[options.interpolationkey] || {}; + var l = valOptions.locale || valOptions.lng || options.locale || options.lng || lng; + formatted = _this.formats[formatName](mem, l, _objectSpread$4(_objectSpread$4(_objectSpread$4({}, formatOptions), options), valOptions)); + } catch (error) { + _this.logger.warn(error); + } -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.signal) !== 'object' || _typeof(args.previousSignal) != 'object') { - throw new TypeError(); - } + return formatted; + } else { + _this.logger.warn("there was no format function for ".concat(formatName)); + } - var sf = 0; + return mem; + }, value); + return result; + } + }]); - for (var i = -(args.bufferSize / 2); i < signal.length / 2 - 1; i++) { - x = Math.abs(args.signal[i]) - Math.abs(args.previousSignal[i]); - sf += (x + Math.abs(x)) / 2; - } + return Formatter; +}(); - return sf; -}); +function ownKeys$5(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } -/***/ }), +function _objectSpread$5(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$5(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$5(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } -/***/ "./src/extractors/spectralKurtosis.js": -/*!********************************************!*\ - !*** ./src/extractors/spectralKurtosis.js ***! - \********************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +function _createSuper$2(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$2(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } +function _isNativeReflectConstruct$2() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function remove(arr, what) { + var found = arr.indexOf(what); -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].ampSpectrum) !== 'object') { - throw new TypeError(); + while (found !== -1) { + arr.splice(found, 1); + found = arr.indexOf(what); } +} - var ampspec = arguments[0].ampSpectrum; - var mu1 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, ampspec); - var mu2 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(2, ampspec); - var mu3 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(3, ampspec); - var mu4 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(4, ampspec); - var numerator = -3 * Math.pow(mu1, 4) + 6 * mu1 * mu2 - 4 * mu1 * mu3 + mu4; - var denominator = Math.pow(Math.sqrt(mu2 - Math.pow(mu1, 2)), 4); - return numerator / denominator; -}); +var Connector = function (_EventEmitter) { + _inherits__default['default'](Connector, _EventEmitter); -/***/ }), + var _super = _createSuper$2(Connector); -/***/ "./src/extractors/spectralRolloff.js": -/*!*******************************************!*\ - !*** ./src/extractors/spectralRolloff.js ***! - \*******************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + function Connector(backend, store, services) { + var _this; -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].ampSpectrum) !== 'object') { - throw new TypeError(); - } + _classCallCheck__default['default'](this, Connector); - var ampspec = arguments[0].ampSpectrum; //calculate nyquist bin + _this = _super.call(this); - var nyqBin = arguments[0].sampleRate / (2 * (ampspec.length - 1)); - var ec = 0; + if (isIE10) { + EventEmitter.call(_assertThisInitialized__default['default'](_this)); + } - for (var i = 0; i < ampspec.length; i++) { - ec += ampspec[i]; - } + _this.backend = backend; + _this.store = store; + _this.services = services; + _this.languageUtils = services.languageUtils; + _this.options = options; + _this.logger = baseLogger.create('backendConnector'); + _this.state = {}; + _this.queue = []; - var threshold = 0.99 * ec; - var n = ampspec.length - 1; + if (_this.backend && _this.backend.init) { + _this.backend.init(services, options.backend, options); + } - while (ec > threshold && n >= 0) { - ec -= ampspec[n]; - --n; + return _this; } - return (n + 1) * nyqBin; -}); + _createClass__default['default'](Connector, [{ + key: "queueLoad", + value: function queueLoad(languages, namespaces, options, callback) { + var _this2 = this; -/***/ }), + var toLoad = []; + var pending = []; + var toLoadLanguages = []; + var toLoadNamespaces = []; + languages.forEach(function (lng) { + var hasAllNamespaces = true; + namespaces.forEach(function (ns) { + var name = "".concat(lng, "|").concat(ns); -/***/ "./src/extractors/spectralSkewness.js": -/*!********************************************!*\ - !*** ./src/extractors/spectralSkewness.js ***! - \********************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (!options.reload && _this2.store.hasResourceBundle(lng, ns)) { + _this2.state[name] = 2; + } else if (_this2.state[name] < 0) ; else if (_this2.state[name] === 1) { + if (pending.indexOf(name) < 0) pending.push(name); + } else { + _this2.state[name] = 1; + hasAllNamespaces = false; + if (pending.indexOf(name) < 0) pending.push(name); + if (toLoad.indexOf(name) < 0) toLoad.push(name); + if (toLoadNamespaces.indexOf(ns) < 0) toLoadNamespaces.push(ns); + } + }); + if (!hasAllNamespaces) toLoadLanguages.push(lng); + }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + if (toLoad.length || pending.length) { + this.queue.push({ + pending: pending, + loaded: {}, + errors: [], + callback: callback + }); + } + return { + toLoad: toLoad, + pending: pending, + toLoadLanguages: toLoadLanguages, + toLoadNamespaces: toLoadNamespaces + }; + } + }, { + key: "loaded", + value: function loaded(name, err, data) { + var s = name.split('|'); + var lng = s[0]; + var ns = s[1]; + if (err) this.emit('failedLoading', lng, ns, err); -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.ampSpectrum) !== 'object') { - throw new TypeError(); - } + if (data) { + this.store.addResourceBundle(lng, ns, data); + } - var mu1 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, args.ampSpectrum); - var mu2 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(2, args.ampSpectrum); - var mu3 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(3, args.ampSpectrum); - var numerator = 2 * Math.pow(mu1, 3) - 3 * mu1 * mu2 + mu3; - var denominator = Math.pow(Math.sqrt(mu2 - Math.pow(mu1, 2)), 3); - return numerator / denominator; -}); + this.state[name] = err ? -1 : 2; + var loaded = {}; + this.queue.forEach(function (q) { + pushPath(q.loaded, [lng], ns); + remove(q.pending, name); + if (err) q.errors.push(err); -/***/ }), + if (q.pending.length === 0 && !q.done) { + Object.keys(q.loaded).forEach(function (l) { + if (!loaded[l]) loaded[l] = []; -/***/ "./src/extractors/spectralSlope.js": -/*!*****************************************!*\ - !*** ./src/extractors/spectralSlope.js ***! - \*****************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (q.loaded[l].length) { + q.loaded[l].forEach(function (ns) { + if (loaded[l].indexOf(ns) < 0) loaded[l].push(ns); + }); + } + }); + q.done = true; -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + if (q.errors.length) { + q.callback(q.errors); + } else { + q.callback(); + } + } + }); + this.emit('loaded', loaded); + this.queue = this.queue.filter(function (q) { + return !q.done; + }); + } + }, { + key: "read", + value: function read(lng, ns, fcName) { + var _this3 = this; -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.ampSpectrum) !== 'object') { - throw new TypeError(); - } //linear regression + var tried = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; + var wait = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 350; + var callback = arguments.length > 5 ? arguments[5] : undefined; + if (!lng.length) return callback(null, {}); + return this.backend[fcName](lng, ns, function (err, data) { + if (err && data && tried < 5) { + setTimeout(function () { + _this3.read.call(_this3, lng, ns, fcName, tried + 1, wait * 2, callback); + }, wait); + return; + } + callback(err, data); + }); + } + }, { + key: "prepareLoading", + value: function prepareLoading(languages, namespaces) { + var _this4 = this; - var ampSum = 0; - var freqSum = 0; - var freqs = new Float32Array(args.ampSpectrum.length); - var powFreqSum = 0; - var ampFreqSum = 0; + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + var callback = arguments.length > 3 ? arguments[3] : undefined; - for (var i = 0; i < args.ampSpectrum.length; i++) { - ampSum += args.ampSpectrum[i]; - var curFreq = i * args.sampleRate / args.bufferSize; - freqs[i] = curFreq; - powFreqSum += curFreq * curFreq; - freqSum += curFreq; - ampFreqSum += curFreq * args.ampSpectrum[i]; - } + if (!this.backend) { + this.logger.warn('No backend was added via i18next.use. Will not load resources.'); + return callback && callback(); + } - return (args.ampSpectrum.length * ampFreqSum - freqSum * ampSum) / (ampSum * (powFreqSum - Math.pow(freqSum, 2))); -}); + if (typeof languages === 'string') languages = this.languageUtils.toResolveHierarchy(languages); + if (typeof namespaces === 'string') namespaces = [namespaces]; + var toLoad = this.queueLoad(languages, namespaces, options, callback); -/***/ }), + if (!toLoad.toLoad.length) { + if (!toLoad.pending.length) callback(); + return null; + } -/***/ "./src/extractors/spectralSpread.js": -/*!******************************************!*\ - !*** ./src/extractors/spectralSpread.js ***! - \******************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + toLoad.toLoad.forEach(function (name) { + _this4.loadOne(name); + }); + } + }, { + key: "load", + value: function load(languages, namespaces, callback) { + this.prepareLoading(languages, namespaces, {}, callback); + } + }, { + key: "reload", + value: function reload(languages, namespaces, callback) { + this.prepareLoading(languages, namespaces, { + reload: true + }, callback); + } + }, { + key: "loadOne", + value: function loadOne(name) { + var _this5 = this; -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + var prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var s = name.split('|'); + var lng = s[0]; + var ns = s[1]; + this.read(lng, ns, 'read', undefined, undefined, function (err, data) { + if (err) _this5.logger.warn("".concat(prefix, "loading namespace ").concat(ns, " for language ").concat(lng, " failed"), err); + if (!err && data) _this5.logger.log("".concat(prefix, "loaded namespace ").concat(ns, " for language ").concat(lng), data); + _this5.loaded(name, err, data); + }); + } + }, { + key: "saveMissing", + value: function saveMissing(languages, namespace, key, fallbackValue, isUpdate) { + var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; -/* harmony default export */ __webpack_exports__["default"] = (function (args) { - if (_typeof(args.ampSpectrum) !== 'object') { - throw new TypeError(); - } + if (this.services.utils && this.services.utils.hasLoadedNamespace && !this.services.utils.hasLoadedNamespace(namespace)) { + this.logger.warn("did not save key \"".concat(key, "\" as the namespace \"").concat(namespace, "\" was not yet loaded"), 'This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!'); + return; + } - return Math.sqrt(Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(2, args.ampSpectrum) - Math.pow(Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, args.ampSpectrum), 2)); -}); + if (key === undefined || key === null || key === '') return; -/***/ }), + if (this.backend && this.backend.create) { + this.backend.create(languages, namespace, key, fallbackValue, null, _objectSpread$5(_objectSpread$5({}, options), {}, { + isUpdate: isUpdate + })); + } -/***/ "./src/extractors/zcr.js": -/*!*******************************!*\ - !*** ./src/extractors/zcr.js ***! - \*******************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (!languages || !languages[0]) return; + this.store.addResource(languages[0], namespace, key, fallbackValue); + } + }]); -"use strict"; -__webpack_require__.r(__webpack_exports__); -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + return Connector; +}(EventEmitter); -/* harmony default export */ __webpack_exports__["default"] = (function () { - if (_typeof(arguments[0].signal) !== 'object') { - throw new TypeError(); - } +function get() { + return { + debug: false, + initImmediate: true, + ns: ['translation'], + defaultNS: ['translation'], + fallbackLng: ['dev'], + fallbackNS: false, + supportedLngs: false, + nonExplicitSupportedLngs: false, + load: 'all', + preload: false, + simplifyPluralSuffix: true, + keySeparator: '.', + nsSeparator: ':', + pluralSeparator: '_', + contextSeparator: '_', + partialBundledLanguages: false, + saveMissing: false, + updateMissing: false, + saveMissingTo: 'fallback', + saveMissingPlurals: true, + missingKeyHandler: false, + missingInterpolationHandler: false, + postProcess: false, + postProcessPassResolved: false, + returnNull: true, + returnEmptyString: true, + returnObjects: false, + joinArrays: false, + returnedObjectHandler: false, + parseMissingKeyHandler: false, + appendNamespaceToMissingKey: false, + appendNamespaceToCIMode: false, + overloadTranslationOptionHandler: function handle(args) { + var ret = {}; + if (_typeof__default['default'](args[1]) === 'object') ret = args[1]; + if (typeof args[1] === 'string') ret.defaultValue = args[1]; + if (typeof args[2] === 'string') ret.tDescription = args[2]; - var zcr = 0; + if (_typeof__default['default'](args[2]) === 'object' || _typeof__default['default'](args[3]) === 'object') { + var options = args[3] || args[2]; + Object.keys(options).forEach(function (key) { + ret[key] = options[key]; + }); + } - for (var i = 1; i < arguments[0].signal.length; i++) { - if (arguments[0].signal[i - 1] >= 0 && arguments[0].signal[i] < 0 || arguments[0].signal[i - 1] < 0 && arguments[0].signal[i] >= 0) { - zcr++; + return ret; + }, + interpolation: { + escapeValue: true, + format: function format(value, _format, lng, options) { + return value; + }, + prefix: '{{', + suffix: '}}', + formatSeparator: ',', + unescapePrefix: '-', + nestingPrefix: '$t(', + nestingSuffix: ')', + nestingOptionsSeparator: ',', + maxReplaces: 1000, + skipOnVariables: true } + }; +} +function transformOptions(options) { + if (typeof options.ns === 'string') options.ns = [options.ns]; + if (typeof options.fallbackLng === 'string') options.fallbackLng = [options.fallbackLng]; + if (typeof options.fallbackNS === 'string') options.fallbackNS = [options.fallbackNS]; + + if (options.supportedLngs && options.supportedLngs.indexOf('cimode') < 0) { + options.supportedLngs = options.supportedLngs.concat(['cimode']); } - return zcr; -}); + return options; +} -/***/ }), +function ownKeys$6(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } -/***/ "./src/featureExtractors.js": -/*!**********************************!*\ - !*** ./src/featureExtractors.js ***! - \**********************************/ -/*! exports provided: buffer, rms, energy, complexSpectrum, spectralSlope, spectralCentroid, spectralRolloff, spectralFlatness, spectralSpread, spectralSkewness, spectralKurtosis, amplitudeSpectrum, zcr, loudness, perceptualSpread, perceptualSharpness, powerSpectrum, mfcc, chroma, spectralFlux */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +function _objectSpread$6(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$6(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$6(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return buffer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "complexSpectrum", function() { return complexSpectrum; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "amplitudeSpectrum", function() { return amplitudeSpectrum; }); -/* harmony import */ var _extractors_rms__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractors/rms */ "./src/extractors/rms.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "rms", function() { return _extractors_rms__WEBPACK_IMPORTED_MODULE_0__["default"]; }); +function _createSuper$3(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$3(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } -/* harmony import */ var _extractors_energy__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./extractors/energy */ "./src/extractors/energy.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "energy", function() { return _extractors_energy__WEBPACK_IMPORTED_MODULE_1__["default"]; }); +function _isNativeReflectConstruct$3() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } -/* harmony import */ var _extractors_spectralSlope__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./extractors/spectralSlope */ "./src/extractors/spectralSlope.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralSlope", function() { return _extractors_spectralSlope__WEBPACK_IMPORTED_MODULE_2__["default"]; }); +function noop() {} -/* harmony import */ var _extractors_spectralCentroid__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./extractors/spectralCentroid */ "./src/extractors/spectralCentroid.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralCentroid", function() { return _extractors_spectralCentroid__WEBPACK_IMPORTED_MODULE_3__["default"]; }); +function bindMemberFunctions(inst) { + var mems = Object.getOwnPropertyNames(Object.getPrototypeOf(inst)); + mems.forEach(function (mem) { + if (typeof inst[mem] === 'function') { + inst[mem] = inst[mem].bind(inst); + } + }); +} -/* harmony import */ var _extractors_spectralRolloff__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./extractors/spectralRolloff */ "./src/extractors/spectralRolloff.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralRolloff", function() { return _extractors_spectralRolloff__WEBPACK_IMPORTED_MODULE_4__["default"]; }); +var I18n = function (_EventEmitter) { + _inherits__default['default'](I18n, _EventEmitter); -/* harmony import */ var _extractors_spectralFlatness__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./extractors/spectralFlatness */ "./src/extractors/spectralFlatness.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralFlatness", function() { return _extractors_spectralFlatness__WEBPACK_IMPORTED_MODULE_5__["default"]; }); + var _super = _createSuper$3(I18n); -/* harmony import */ var _extractors_spectralSpread__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./extractors/spectralSpread */ "./src/extractors/spectralSpread.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralSpread", function() { return _extractors_spectralSpread__WEBPACK_IMPORTED_MODULE_6__["default"]; }); + function I18n() { + var _this; -/* harmony import */ var _extractors_spectralSkewness__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./extractors/spectralSkewness */ "./src/extractors/spectralSkewness.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralSkewness", function() { return _extractors_spectralSkewness__WEBPACK_IMPORTED_MODULE_7__["default"]; }); + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var callback = arguments.length > 1 ? arguments[1] : undefined; -/* harmony import */ var _extractors_spectralKurtosis__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./extractors/spectralKurtosis */ "./src/extractors/spectralKurtosis.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralKurtosis", function() { return _extractors_spectralKurtosis__WEBPACK_IMPORTED_MODULE_8__["default"]; }); + _classCallCheck__default['default'](this, I18n); -/* harmony import */ var _extractors_zcr__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./extractors/zcr */ "./src/extractors/zcr.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zcr", function() { return _extractors_zcr__WEBPACK_IMPORTED_MODULE_9__["default"]; }); + _this = _super.call(this); -/* harmony import */ var _extractors_loudness__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./extractors/loudness */ "./src/extractors/loudness.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "loudness", function() { return _extractors_loudness__WEBPACK_IMPORTED_MODULE_10__["default"]; }); + if (isIE10) { + EventEmitter.call(_assertThisInitialized__default['default'](_this)); + } -/* harmony import */ var _extractors_perceptualSpread__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./extractors/perceptualSpread */ "./src/extractors/perceptualSpread.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "perceptualSpread", function() { return _extractors_perceptualSpread__WEBPACK_IMPORTED_MODULE_11__["default"]; }); + _this.options = transformOptions(options); + _this.services = {}; + _this.logger = baseLogger; + _this.modules = { + external: [] + }; + bindMemberFunctions(_assertThisInitialized__default['default'](_this)); -/* harmony import */ var _extractors_perceptualSharpness__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./extractors/perceptualSharpness */ "./src/extractors/perceptualSharpness.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "perceptualSharpness", function() { return _extractors_perceptualSharpness__WEBPACK_IMPORTED_MODULE_12__["default"]; }); + if (callback && !_this.isInitialized && !options.isClone) { + if (!_this.options.initImmediate) { + _this.init(options, callback); -/* harmony import */ var _extractors_mfcc__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./extractors/mfcc */ "./src/extractors/mfcc.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mfcc", function() { return _extractors_mfcc__WEBPACK_IMPORTED_MODULE_13__["default"]; }); + return _possibleConstructorReturn__default['default'](_this, _assertThisInitialized__default['default'](_this)); + } -/* harmony import */ var _extractors_chroma__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./extractors/chroma */ "./src/extractors/chroma.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "chroma", function() { return _extractors_chroma__WEBPACK_IMPORTED_MODULE_14__["default"]; }); + setTimeout(function () { + _this.init(options, callback); + }, 0); + } -/* harmony import */ var _extractors_powerSpectrum__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./extractors/powerSpectrum */ "./src/extractors/powerSpectrum.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "powerSpectrum", function() { return _extractors_powerSpectrum__WEBPACK_IMPORTED_MODULE_15__["default"]; }); + return _this; + } -/* harmony import */ var _extractors_spectralFlux__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./extractors/spectralFlux */ "./src/extractors/spectralFlux.js"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralFlux", function() { return _extractors_spectralFlux__WEBPACK_IMPORTED_MODULE_16__["default"]; }); + _createClass__default['default'](I18n, [{ + key: "init", + value: function init() { + var _this2 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var callback = arguments.length > 1 ? arguments[1] : undefined; + if (typeof options === 'function') { + callback = options; + options = {}; + } + if (!options.defaultNS && options.ns) { + if (typeof options.ns === 'string') { + options.defaultNS = options.ns; + } else if (options.ns.indexOf('translation') < 0) { + options.defaultNS = options.ns[0]; + } + } + var defOpts = get(); + this.options = _objectSpread$6(_objectSpread$6(_objectSpread$6({}, defOpts), this.options), transformOptions(options)); + if (this.options.compatibilityAPI !== 'v1') { + this.options.interpolation = _objectSpread$6(_objectSpread$6({}, defOpts.interpolation), this.options.interpolation); + } + if (options.keySeparator !== undefined) { + this.options.userDefinedKeySeparator = options.keySeparator; + } + if (options.nsSeparator !== undefined) { + this.options.userDefinedNsSeparator = options.nsSeparator; + } + function createClassOnDemand(ClassOrObject) { + if (!ClassOrObject) return null; + if (typeof ClassOrObject === 'function') return new ClassOrObject(); + return ClassOrObject; + } + if (!this.options.isClone) { + if (this.modules.logger) { + baseLogger.init(createClassOnDemand(this.modules.logger), this.options); + } else { + baseLogger.init(null, this.options); + } + var formatter; + if (this.modules.formatter) { + formatter = this.modules.formatter; + } else if (typeof Intl !== 'undefined') { + formatter = Formatter; + } + var lu = new LanguageUtil(this.options); + this.store = new ResourceStore(this.options.resources, this.options); + var s = this.services; + s.logger = baseLogger; + s.resourceStore = this.store; + s.languageUtils = lu; + s.pluralResolver = new PluralResolver(lu, { + prepend: this.options.pluralSeparator, + compatibilityJSON: this.options.compatibilityJSON, + simplifyPluralSuffix: this.options.simplifyPluralSuffix + }); + if (formatter && (!this.options.interpolation.format || this.options.interpolation.format === defOpts.interpolation.format)) { + s.formatter = createClassOnDemand(formatter); + s.formatter.init(s, this.options); + this.options.interpolation.format = s.formatter.format.bind(s.formatter); + } + s.interpolator = new Interpolator(this.options); + s.utils = { + hasLoadedNamespace: this.hasLoadedNamespace.bind(this) + }; + s.backendConnector = new Connector(createClassOnDemand(this.modules.backend), s.resourceStore, s, this.options); + s.backendConnector.on('*', function (event) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + _this2.emit.apply(_this2, [event].concat(args)); + }); + if (this.modules.languageDetector) { + s.languageDetector = createClassOnDemand(this.modules.languageDetector); + s.languageDetector.init(s, this.options.detection, this.options); + } + if (this.modules.i18nFormat) { + s.i18nFormat = createClassOnDemand(this.modules.i18nFormat); + if (s.i18nFormat.init) s.i18nFormat.init(this); + } + this.translator = new Translator(this.services, this.options); + this.translator.on('*', function (event) { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } -var buffer = function buffer(args) { - return args.signal; -}; + _this2.emit.apply(_this2, [event].concat(args)); + }); + this.modules.external.forEach(function (m) { + if (m.init) m.init(_this2); + }); + } -var complexSpectrum = function complexSpectrum(args) { - return args.complexSpectrum; -}; + this.format = this.options.interpolation.format; + if (!callback) callback = noop; -var amplitudeSpectrum = function amplitudeSpectrum(args) { - return args.ampSpectrum; -}; + if (this.options.fallbackLng && !this.services.languageDetector && !this.options.lng) { + var codes = this.services.languageUtils.getFallbackCodes(this.options.fallbackLng); + if (codes.length > 0 && codes[0] !== 'dev') this.options.lng = codes[0]; + } + if (!this.services.languageDetector && !this.options.lng) { + this.logger.warn('init: no languageDetector is used and no lng is defined'); + } + var storeApi = ['getResource', 'hasResourceBundle', 'getResourceBundle', 'getDataByLanguage']; + storeApi.forEach(function (fcName) { + _this2[fcName] = function () { + var _this2$store; -/***/ }), + return (_this2$store = _this2.store)[fcName].apply(_this2$store, arguments); + }; + }); + var storeApiChained = ['addResource', 'addResources', 'addResourceBundle', 'removeResourceBundle']; + storeApiChained.forEach(function (fcName) { + _this2[fcName] = function () { + var _this2$store2; -/***/ "./src/index.js": -/*!**********************!*\ - !*** ./src/index.js ***! - \**********************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { + (_this2$store2 = _this2.store)[fcName].apply(_this2$store2, arguments); -module.exports = __webpack_require__(/*! ./main */ "./src/main.js")["default"]; + return _this2; + }; + }); + var deferred = defer(); -/***/ }), + var load = function load() { + var finish = function finish(err, t) { + if (_this2.isInitialized && !_this2.initializedStoreOnce) _this2.logger.warn('init: i18next is already initialized. You should call init just once!'); + _this2.isInitialized = true; + if (!_this2.options.isClone) _this2.logger.log('initialized', _this2.options); -/***/ "./src/main.js": -/*!*********************!*\ - !*** ./src/main.js ***! - \*********************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + _this2.emit('initialized', _this2.options); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/utilities.js"); -/* harmony import */ var _featureExtractors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./featureExtractors */ "./src/featureExtractors.js"); -/* harmony import */ var fftjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! fftjs */ "./node_modules/fftjs/dist/fft.js"); -/* harmony import */ var fftjs__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(fftjs__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _meyda_wa__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./meyda-wa */ "./src/meyda-wa.js"); -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + deferred.resolve(t); + callback(err, t); + }; -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + if (_this2.languages && _this2.options.compatibilityAPI !== 'v1' && !_this2.isInitialized) return finish(null, _this2.t.bind(_this2)); + + _this2.changeLanguage(_this2.options.lng, finish); + }; + if (this.options.resources || !this.options.initImmediate) { + load(); + } else { + setTimeout(load, 0); + } + return deferred; + } + }, { + key: "loadResources", + value: function loadResources(language) { + var _this3 = this; + var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop; + var usedCallback = callback; + var usedLng = typeof language === 'string' ? language : this.language; + if (typeof language === 'function') usedCallback = language; + if (!this.options.resources || this.options.partialBundledLanguages) { + if (usedLng && usedLng.toLowerCase() === 'cimode') return usedCallback(); + var toLoad = []; -/** - * Meyda Module - * @module meyda - */ + var append = function append(lng) { + if (!lng) return; -/** - * Options for constructing a MeydaAnalyzer - * @typedef {Object} MeydaOptions - * @property {AudioContext} audioContext - The Audio Context for the MeydaAnalyzer to operate in. - * @property {AudioNode} source - The Audio Node for Meyda to listen to. - * @property {number} [bufferSize] - The size of the buffer. - * @property {number} [hopSize] - The hop size between buffers. - * @property {number} [sampleRate] - The number of samples per second in the audio context. - * @property {Function} [callback] - A function to receive the frames of audio features - * @property {string} [windowingFunction] - The Windowing Function to apply to the signal before transformation to the frequency domain - * @property {string|Array.} [featureExtractors] - Specify the feature extractors you want to run on the audio. - * @property {boolean} [startImmediately] - Pass `true` to start feature extraction immediately - * @property {number} [numberOfMFCCCoefficients] - The number of MFCC co-efficients that the MFCC feature extractor should return - */ + var lngs = _this3.services.languageUtils.toResolveHierarchy(lng); -/** - * Web Audio context - * Either an {@link AudioContext|https://developer.mozilla.org/en-US/docs/Web/API/AudioContext} - * or an {@link OfflineAudioContext|https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext} - * @typedef {Object} AudioContext - */ + lngs.forEach(function (l) { + if (toLoad.indexOf(l) < 0) toLoad.push(l); + }); + }; -/** - * AudioNode - * A Web AudioNode - * @typedef {Object} AudioNode - */ + if (!usedLng) { + var fallbacks = this.services.languageUtils.getFallbackCodes(this.options.fallbackLng); + fallbacks.forEach(function (l) { + return append(l); + }); + } else { + append(usedLng); + } -/** - * ScriptProcessorNode - * A Web Audio ScriptProcessorNode - * @typedef {Object} ScriptProcessorNode - */ + if (this.options.preload) { + this.options.preload.forEach(function (l) { + return append(l); + }); + } -/** - * @class Meyda - * @hideconstructor - * @classdesc - * The schema for the default export of the Meyda library. - * @example - * var Meyda = require('meyda'); - */ + this.services.backendConnector.load(toLoad, this.options.ns, usedCallback); + } else { + usedCallback(null); + } + } + }, { + key: "reloadResources", + value: function reloadResources(lngs, ns, callback) { + var deferred = defer(); + if (!lngs) lngs = this.languages; + if (!ns) ns = this.options.ns; + if (!callback) callback = noop; + this.services.backendConnector.reload(lngs, ns, function (err) { + deferred.resolve(); + callback(err); + }); + return deferred; + } + }, { + key: "use", + value: function use(module) { + if (!module) throw new Error('You are passing an undefined module! Please check the object you are passing to i18next.use()'); + if (!module.type) throw new Error('You are passing a wrong module! Please check the object you are passing to i18next.use()'); -var Meyda = { - /** - * Meyda stores a reference to the relevant audio context here for use inside - * the Web Audio API. - * @instance - * @member {AudioContext} - */ - audioContext: null, + if (module.type === 'backend') { + this.modules.backend = module; + } - /** - * Meyda keeps an internal ScriptProcessorNode in which it runs audio feature - * extraction. The ScriptProcessorNode is stored in this member variable. - * @instance - * @member {ScriptProcessorNode} - */ - spn: null, + if (module.type === 'logger' || module.log && module.warn && module.error) { + this.modules.logger = module; + } - /** - * The length of each buffer that Meyda will extract audio on. When recieving - * input via the Web Audio API, the Script Processor Node chunks incoming audio - * into arrays of this length. Longer buffers allow for more precision in the - * frequency domain, but increase the amount of time it takes for Meyda to - * output a set of audio features for the buffer. You can calculate how many - * sets of audio features Meyda will output per second by dividing the - * buffer size by the sample rate. If you're using Meyda for visualisation, - * make sure that you're collecting audio features at a rate that's faster - * than or equal to the video frame rate you expect. - * @instance - * @member {number} - */ - bufferSize: 512, + if (module.type === 'languageDetector') { + this.modules.languageDetector = module; + } - /** - * The number of samples per second of the incoming audio. This affects - * feature extraction outside of the context of the Web Audio API, and must be - * set accurately - otherwise calculations will be off. - * @instance - * @member {number} - */ - sampleRate: 44100, + if (module.type === 'i18nFormat') { + this.modules.i18nFormat = module; + } - /** - * The number of Mel bands to use in the Mel Frequency Cepstral Co-efficients - * feature extractor - * @instance - * @member {number} - */ - melBands: 26, + if (module.type === 'postProcessor') { + postProcessor.addPostProcessor(module); + } - /** - * The number of bands to divide the spectrum into for the Chroma feature - * extractor. 12 is the standard number of semitones per octave in the western - * music tradition, but Meyda can use an arbitrary number of bands, which - * can be useful for microtonal music. - * @instance - * @member {number} - */ - chromaBands: 12, + if (module.type === 'formatter') { + this.modules.formatter = module; + } - /** - * A function you can provide that will be called for each buffer that Meyda - * receives from its source node - * @instance - * @member {Function} - */ - callback: null, + if (module.type === '3rdParty') { + this.modules.external.push(module); + } - /** - * Specify the windowing function to apply to the buffer before the - * transformation from the time domain to the frequency domain is performed - * - * The default windowing function is the hanning window. - * - * @instance - * @member {string} - */ - windowingFunction: 'hanning', + return this; + } + }, { + key: "changeLanguage", + value: function changeLanguage(lng, callback) { + var _this4 = this; - /** - * @member {object} - */ - featureExtractors: _featureExtractors__WEBPACK_IMPORTED_MODULE_1__, - EXTRACTION_STARTED: false, + this.isLanguageChangingTo = lng; + var deferred = defer(); + this.emit('languageChanging', lng); - /** - * The number of MFCC co-efficients that the MFCC feature extractor should return - * @instance - * @member {number} - */ - numberOfMFCCCoefficients: 13, - _featuresToExtract: [], - windowing: _utilities__WEBPACK_IMPORTED_MODULE_0__["applyWindow"], - _errors: { - notPow2: new Error('Meyda: Buffer size must be a power of 2, e.g. 64 or 512'), - featureUndef: new Error('Meyda: No features defined.'), - invalidFeatureFmt: new Error('Meyda: Invalid feature format'), - invalidInput: new Error('Meyda: Invalid input.'), - noAC: new Error('Meyda: No AudioContext specified.'), - noSource: new Error('Meyda: No source node specified.') - }, + var setLngProps = function setLngProps(l) { + _this4.language = l; + _this4.languages = _this4.services.languageUtils.toResolveHierarchy(l); + _this4.resolvedLanguage = undefined; + if (['cimode', 'dev'].indexOf(l) > -1) return; - /** - * @summary - * Create a MeydaAnalyzer - * - * A factory function for creating a MeydaAnalyzer, the interface for using - * Meyda in the context of Web Audio. - * - * @method - * @param {MeydaOptions} options Options - an object containing configuration - * @returns {MeydaAnalyzer} - * @example - * const analyzer = Meyda.createMeydaAnalyzer({ - * "audioContext": audioContext, - * "source": source, - * "bufferSize": 512, - * "featureExtractors": ["rms"], - * "inputs": 2, - * "callback": features => { - * levelRangeElement.value = features.rms; - * } - * }); - */ - createMeydaAnalyzer: function createMeydaAnalyzer(options) { - return new _meyda_wa__WEBPACK_IMPORTED_MODULE_3__["MeydaAnalyzer"](options, Object.assign({}, Meyda)); - }, + for (var li = 0; li < _this4.languages.length; li++) { + var lngInLngs = _this4.languages[li]; + if (['cimode', 'dev'].indexOf(lngInLngs) > -1) continue; - /** - * Extract an audio feature from a buffer - * - * Unless `meyda.windowingFunction` is set otherwise, `extract` will - * internally apply a hanning window to the buffer prior to conversion into - * the frequency domain. - * - * @function - * @param {(string|Array.)} feature - the feature you want to extract - * @param {Array.} signal - * An array of numbers that represents the signal. It should be of length - * `meyda.bufferSize` - * @param {Array.} [previousSignal] - the previous buffer - * @returns {object} Features - * @example - * meyda.bufferSize = 2048; - * const features = meyda.extract(['zcr', 'spectralCentroid'], signal); - */ - extract: function extract(feature, signal, previousSignal) { - var _this = this; + if (_this4.store.hasLanguageSomeTranslations(lngInLngs)) { + _this4.resolvedLanguage = lngInLngs; + break; + } + } + }; - if (!signal) throw this._errors.invalidInput;else if (_typeof(signal) != 'object') throw this._errors.invalidInput;else if (!feature) throw this._errors.featureUndef;else if (!_utilities__WEBPACK_IMPORTED_MODULE_0__["isPowerOfTwo"](signal.length)) throw this._errors.notPow2; + var done = function done(err, l) { + if (l) { + setLngProps(l); - if (typeof this.barkScale == 'undefined' || this.barkScale.length != this.bufferSize) { - this.barkScale = _utilities__WEBPACK_IMPORTED_MODULE_0__["createBarkScale"](this.bufferSize, this.sampleRate, this.bufferSize); - } // Recalculate mel bank if buffer length changed + _this4.translator.changeLanguage(l); + _this4.isLanguageChangingTo = undefined; - if (typeof this.melFilterBank == 'undefined' || this.barkScale.length != this.bufferSize || this.melFilterBank.length != this.melBands) { - this.melFilterBank = _utilities__WEBPACK_IMPORTED_MODULE_0__["createMelFilterBank"](Math.max(this.melBands, this.numberOfMFCCCoefficients), this.sampleRate, this.bufferSize); - } // Recalculate chroma bank if buffer length changed + _this4.emit('languageChanged', l); + _this4.logger.log('languageChanged', l); + } else { + _this4.isLanguageChangingTo = undefined; + } - if (typeof this.chromaFilterBank == 'undefined' || this.chromaFilterBank.length != this.chromaBands) { - this.chromaFilterBank = _utilities__WEBPACK_IMPORTED_MODULE_0__["createChromaFilterBank"](this.chromaBands, this.sampleRate, this.bufferSize); - } + deferred.resolve(function () { + return _this4.t.apply(_this4, arguments); + }); + if (callback) callback(err, function () { + return _this4.t.apply(_this4, arguments); + }); + }; - if (typeof signal.buffer == 'undefined') { - //signal is a normal array, convert to F32A - this.signal = _utilities__WEBPACK_IMPORTED_MODULE_0__["arrayToTyped"](signal); - } else { - this.signal = signal; - } + var setLng = function setLng(lngs) { + if (!lng && !lngs && _this4.services.languageDetector) lngs = []; + var l = typeof lngs === 'string' ? lngs : _this4.services.languageUtils.getBestMatchFromCodes(lngs); - var preparedSignal = prepareSignalWithSpectrum(signal, this.windowingFunction, this.bufferSize); - this.signal = preparedSignal.windowedSignal; - this.complexSpectrum = preparedSignal.complexSpectrum; - this.ampSpectrum = preparedSignal.ampSpectrum; + if (l) { + if (!_this4.language) { + setLngProps(l); + } - if (previousSignal) { - var _preparedSignal = prepareSignalWithSpectrum(previousSignal, this.windowingFunction, this.bufferSize); + if (!_this4.translator.language) _this4.translator.changeLanguage(l); + if (_this4.services.languageDetector) _this4.services.languageDetector.cacheUserLanguage(l); + } - this.previousSignal = _preparedSignal.windowedSignal; - this.previousComplexSpectrum = _preparedSignal.complexSpectrum; - this.previousAmpSpectrum = _preparedSignal.ampSpectrum; - } + _this4.loadResources(l, function (err) { + done(err, l); + }); + }; - var extract = function extract(feature) { - return _this.featureExtractors[feature]({ - ampSpectrum: _this.ampSpectrum, - chromaFilterBank: _this.chromaFilterBank, - complexSpectrum: _this.complexSpectrum, - signal: _this.signal, - bufferSize: _this.bufferSize, - sampleRate: _this.sampleRate, - barkScale: _this.barkScale, - melFilterBank: _this.melFilterBank, - previousSignal: _this.previousSignal, - previousAmpSpectrum: _this.previousAmpSpectrum, - previousComplexSpectrum: _this.previousComplexSpectrum, - numberOfMFCCCoefficients: _this.numberOfMFCCCoefficients - }); - }; + if (!lng && this.services.languageDetector && !this.services.languageDetector.async) { + setLng(this.services.languageDetector.detect()); + } else if (!lng && this.services.languageDetector && this.services.languageDetector.async) { + this.services.languageDetector.detect(setLng); + } else { + setLng(lng); + } - if (_typeof(feature) === 'object') { - return feature.reduce(function (acc, el) { - return Object.assign({}, acc, _defineProperty({}, el, extract(el))); - }, {}); - } else if (typeof feature === 'string') { - return extract(feature); - } else { - throw this._errors.invalidFeatureFmt; + return deferred; } - } -}; + }, { + key: "getFixedT", + value: function getFixedT(lng, ns, keyPrefix) { + var _this5 = this; -var prepareSignalWithSpectrum = function prepareSignalWithSpectrum(signal, windowingFunction, bufferSize) { - var preparedSignal = {}; + var fixedT = function fixedT(key, opts) { + var options; - if (typeof signal.buffer == 'undefined') { - //signal is a normal array, convert to F32A - preparedSignal.signal = _utilities__WEBPACK_IMPORTED_MODULE_0__["arrayToTyped"](signal); - } else { - preparedSignal.signal = signal; - } + if (_typeof__default['default'](opts) !== 'object') { + for (var _len3 = arguments.length, rest = new Array(_len3 > 2 ? _len3 - 2 : 0), _key3 = 2; _key3 < _len3; _key3++) { + rest[_key3 - 2] = arguments[_key3]; + } - preparedSignal.windowedSignal = _utilities__WEBPACK_IMPORTED_MODULE_0__["applyWindow"](preparedSignal.signal, windowingFunction); - preparedSignal.complexSpectrum = Object(fftjs__WEBPACK_IMPORTED_MODULE_2__["fft"])(preparedSignal.windowedSignal); - preparedSignal.ampSpectrum = new Float32Array(bufferSize / 2); + options = _this5.options.overloadTranslationOptionHandler([key, opts].concat(rest)); + } else { + options = _objectSpread$6({}, opts); + } - for (var i = 0; i < bufferSize / 2; i++) { - preparedSignal.ampSpectrum[i] = Math.sqrt(Math.pow(preparedSignal.complexSpectrum.real[i], 2) + Math.pow(preparedSignal.complexSpectrum.imag[i], 2)); - } + options.lng = options.lng || fixedT.lng; + options.lngs = options.lngs || fixedT.lngs; + options.ns = options.ns || fixedT.ns; + var keySeparator = _this5.options.keySeparator || '.'; + var resultKey = keyPrefix ? "".concat(keyPrefix).concat(keySeparator).concat(key) : key; + return _this5.t(resultKey, options); + }; - return preparedSignal; -}; -/** - * The Meyda class - * @type {Meyda} - */ + if (typeof lng === 'string') { + fixedT.lng = lng; + } else { + fixedT.lngs = lng; + } + fixedT.ns = ns; + fixedT.keyPrefix = keyPrefix; + return fixedT; + } + }, { + key: "t", + value: function t() { + var _this$translator; -/* harmony default export */ __webpack_exports__["default"] = (Meyda); -if (typeof window !== 'undefined') window.Meyda = Meyda; + return this.translator && (_this$translator = this.translator).translate.apply(_this$translator, arguments); + } + }, { + key: "exists", + value: function exists() { + var _this$translator2; -/***/ }), + return this.translator && (_this$translator2 = this.translator).exists.apply(_this$translator2, arguments); + } + }, { + key: "setDefaultNamespace", + value: function setDefaultNamespace(ns) { + this.options.defaultNS = ns; + } + }, { + key: "hasLoadedNamespace", + value: function hasLoadedNamespace(ns) { + var _this6 = this; -/***/ "./src/meyda-wa.js": -/*!*************************!*\ - !*** ./src/meyda-wa.js ***! - \*************************/ -/*! exports provided: MeydaAnalyzer */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeydaAnalyzer", function() { return MeydaAnalyzer; }); -/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/utilities.js"); -/* harmony import */ var _featureExtractors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./featureExtractors */ "./src/featureExtractors.js"); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + if (!this.isInitialized) { + this.logger.warn('hasLoadedNamespace: i18next was not initialized', this.languages); + return false; + } -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + if (!this.languages || !this.languages.length) { + this.logger.warn('hasLoadedNamespace: i18n.languages were undefined or empty', this.languages); + return false; + } -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + var lng = this.resolvedLanguage || this.languages[0]; + var fallbackLng = this.options ? this.options.fallbackLng : false; + var lastLng = this.languages[this.languages.length - 1]; + if (lng.toLowerCase() === 'cimode') return true; + var loadNotPending = function loadNotPending(l, n) { + var loadState = _this6.services.backendConnector.state["".concat(l, "|").concat(n)]; + return loadState === -1 || loadState === 2; + }; -/** - * MeydaAnalyzer - * @classdesc - * Meyda's interface to the Web Audio API. MeydaAnalyzer abstracts an API on - * top of the Web Audio API's ScriptProcessorNode, running the Meyda audio - * feature extractors inside that context. - * - * MeydaAnalyzer's constructor should not be called directly - MeydaAnalyzer - * objects should be generated using the {@link Meyda.createMeydaAnalyzer} - * factory function in the main Meyda class. - * - * @example - * const analyzer = Meyda.createMeydaAnalyzer({ - * "audioContext": audioContext, - * "source": source, - * "bufferSize": 512, - * "featureExtractors": ["rms"], - * "inputs": 2, - * "numberOfMFCCCoefficients": 20 - * "callback": features => { - * levelRangeElement.value = features.rms; - * } - * }); - * @hideconstructor - */ + if (options.precheck) { + var preResult = options.precheck(this, loadNotPending); + if (preResult !== undefined) return preResult; + } -var MeydaAnalyzer = -/*#__PURE__*/ -function () { - function MeydaAnalyzer(options, _this) { - var _this2 = this; + if (this.hasResourceBundle(lng, ns)) return true; + if (!this.services.backendConnector.backend) return true; + if (loadNotPending(lng, ns) && (!fallbackLng || loadNotPending(lastLng, ns))) return true; + return false; + } + }, { + key: "loadNamespaces", + value: function loadNamespaces(ns, callback) { + var _this7 = this; - _classCallCheck(this, MeydaAnalyzer); + var deferred = defer(); - this._m = _this; + if (!this.options.ns) { + callback && callback(); + return Promise.resolve(); + } - if (!options.audioContext) { - throw this._m.errors.noAC; - } else if (options.bufferSize && !_utilities__WEBPACK_IMPORTED_MODULE_0__["isPowerOfTwo"](options.bufferSize)) { - throw this._m._errors.notPow2; - } else if (!options.source) { - throw this._m._errors.noSource; + if (typeof ns === 'string') ns = [ns]; + ns.forEach(function (n) { + if (_this7.options.ns.indexOf(n) < 0) _this7.options.ns.push(n); + }); + this.loadResources(function (err) { + deferred.resolve(); + if (callback) callback(err); + }); + return deferred; } + }, { + key: "loadLanguages", + value: function loadLanguages(lngs, callback) { + var deferred = defer(); + if (typeof lngs === 'string') lngs = [lngs]; + var preloaded = this.options.preload || []; + var newLngs = lngs.filter(function (lng) { + return preloaded.indexOf(lng) < 0; + }); - this._m.audioContext = options.audioContext; // TODO: validate options + if (!newLngs.length) { + if (callback) callback(); + return Promise.resolve(); + } + + this.options.preload = preloaded.concat(newLngs); + this.loadResources(function (err) { + deferred.resolve(); + if (callback) callback(err); + }); + return deferred; + } + }, { + key: "dir", + value: function dir(lng) { + if (!lng) lng = this.resolvedLanguage || (this.languages && this.languages.length > 0 ? this.languages[0] : this.language); + if (!lng) return 'rtl'; + var rtlLngs = ['ar', 'shu', 'sqr', 'ssh', 'xaa', 'yhd', 'yud', 'aao', 'abh', 'abv', 'acm', 'acq', 'acw', 'acx', 'acy', 'adf', 'ads', 'aeb', 'aec', 'afb', 'ajp', 'apc', 'apd', 'arb', 'arq', 'ars', 'ary', 'arz', 'auz', 'avl', 'ayh', 'ayl', 'ayn', 'ayp', 'bbz', 'pga', 'he', 'iw', 'ps', 'pbt', 'pbu', 'pst', 'prp', 'prd', 'ug', 'ur', 'ydd', 'yds', 'yih', 'ji', 'yi', 'hbo', 'men', 'xmn', 'fa', 'jpr', 'peo', 'pes', 'prs', 'dv', 'sam', 'ckb']; + return rtlLngs.indexOf(this.services.languageUtils.getLanguagePartFromCode(lng)) > -1 || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr'; + } + }, { + key: "cloneInstance", + value: function cloneInstance() { + var _this8 = this; - this._m.bufferSize = options.bufferSize || this._m.bufferSize || 256; - this._m.hopSize = options.hopSize || this._m.hopSize || this._m.bufferSize; - this._m.sampleRate = options.sampleRate || this._m.audioContext.sampleRate || 44100; - this._m.callback = options.callback; - this._m.windowingFunction = options.windowingFunction || 'hanning'; - this._m.featureExtractors = _featureExtractors__WEBPACK_IMPORTED_MODULE_1__; - this._m.EXTRACTION_STARTED = options.startImmediately || false; - this._m.channel = typeof options.channel === 'number' ? options.channel : 0; - this._m.inputs = options.inputs || 1; - this._m.outputs = options.outputs || 1; - this._m.numberOfMFCCCoefficients = options.numberOfMFCCCoefficients || this._m.numberOfMFCCCoefficients || 13; //create nodes + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop; - this._m.spn = this._m.audioContext.createScriptProcessor(this._m.bufferSize, this._m.inputs, this._m.outputs); + var mergedOptions = _objectSpread$6(_objectSpread$6(_objectSpread$6({}, this.options), options), { + isClone: true + }); - this._m.spn.connect(this._m.audioContext.destination); + var clone = new I18n(mergedOptions); + var membersToCopy = ['store', 'services', 'language']; + membersToCopy.forEach(function (m) { + clone[m] = _this8[m]; + }); + clone.services = _objectSpread$6({}, this.services); + clone.services.utils = { + hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone) + }; + clone.translator = new Translator(clone.services, clone.options); + clone.translator.on('*', function (event) { + for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { + args[_key4 - 1] = arguments[_key4]; + } - this._m._featuresToExtract = options.featureExtractors || []; //always recalculate BS and MFB when a new Meyda analyzer is created. + clone.emit.apply(clone, [event].concat(args)); + }); + clone.init(mergedOptions, callback); + clone.translator.options = clone.options; + clone.translator.backendConnector.services.utils = { + hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone) + }; + return clone; + } + }, { + key: "toJSON", + value: function toJSON() { + return { + options: this.options, + store: this.store, + language: this.language, + languages: this.languages, + resolvedLanguage: this.resolvedLanguage + }; + } + }]); - this._m.barkScale = _utilities__WEBPACK_IMPORTED_MODULE_0__["createBarkScale"](this._m.bufferSize, this._m.sampleRate, this._m.bufferSize); - this._m.melFilterBank = _utilities__WEBPACK_IMPORTED_MODULE_0__["createMelFilterBank"](Math.max(this._m.melBands, this._m.numberOfMFCCCoefficients), this._m.sampleRate, this._m.bufferSize); - this._m.inputData = null; - this._m.previousInputData = null; - this._m.frame = null; - this._m.previousFrame = null; - this.setSource(options.source); + return I18n; +}(EventEmitter); - this._m.spn.onaudioprocess = function (e) { - if (_this2._m.inputData !== null) { - _this2._m.previousInputData = _this2._m.inputData; - } +_defineProperty__default['default'](I18n, "createInstance", function () { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var callback = arguments.length > 1 ? arguments[1] : undefined; + return new I18n(options, callback); +}); - _this2._m.inputData = e.inputBuffer.getChannelData(_this2._m.channel); +var instance = I18n.createInstance(); +instance.createInstance = I18n.createInstance; - if (!_this2._m.previousInputData) { - var buffer = _this2._m.inputData; - } else { - var buffer = new Float32Array(_this2._m.previousInputData.length + _this2._m.inputData.length - _this2._m.hopSize); - buffer.set(_this2._m.previousInputData.slice(_this2._m.hopSize)); - buffer.set(_this2._m.inputData, _this2._m.previousInputData.length - _this2._m.hopSize); - } +module.exports = instance; - ; - var frames = _utilities__WEBPACK_IMPORTED_MODULE_0__["frame"](buffer, _this2._m.bufferSize, _this2._m.hopSize); - frames.forEach(function (f) { - _this2._m.frame = f; +},{"@babel/runtime/helpers/assertThisInitialized":10,"@babel/runtime/helpers/classCallCheck":11,"@babel/runtime/helpers/createClass":12,"@babel/runtime/helpers/defineProperty":13,"@babel/runtime/helpers/getPrototypeOf":14,"@babel/runtime/helpers/inherits":15,"@babel/runtime/helpers/possibleConstructorReturn":18,"@babel/runtime/helpers/toArray":20,"@babel/runtime/helpers/typeof":21}],90:[function(require,module,exports){ +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] - var features = _this2._m.extract(_this2._m._featuresToExtract, _this2._m.frame, _this2._m.previousFrame); // call callback if applicable + i += d + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} - if (typeof _this2._m.callback === 'function' && _this2._m.EXTRACTION_STARTED) { - _this2._m.callback(features); - } + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} - _this2._m.previousFrame = _this2._m.frame; - }); - }; + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias } - /** - * Start feature extraction - * The audio features will be passed to the callback function that was defined - * in the MeydaOptions that were passed to the factory when constructing the - * MeydaAnalyzer. - * @param {(string|Array.)} [features] - * Change the features that Meyda is extracting. Defaults to the features that - * were set upon construction in the options parameter. - * @example - * analyzer.start('chroma'); - */ + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + value = Math.abs(value) - _createClass(MeydaAnalyzer, [{ - key: "start", - value: function start(features) { - this._m._featuresToExtract = features || this._m._featuresToExtract; - this._m.EXTRACTION_STARTED = true; + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 } - /** - * Stop feature extraction. - * @example - * analyzer.stop(); - */ - }, { - key: "stop", - value: function stop() { - this._m.EXTRACTION_STARTED = false; + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 } - /** - * Set the Audio Node for Meyda to listen to. - * @param {AudioNode} source - The Audio Node for Meyda to listen to - * @example - * analyzer.setSource(audioSourceNode); - */ + } - }, { - key: "setSource", - value: function setSource(source) { - this._m.source && this._m.source.disconnect(this._m.spn); - this._m.source = source; + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - this._m.source.connect(this._m.spn); - } - /** - * Set the channel of the audio node for Meyda to listen to - * @param {number} channel - the index of the channel on the input audio node - * for Meyda to listen to. - * @example - * analyzer.setChannel(0); - */ + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - }, { - key: "setChannel", - value: function setChannel(channel) { - if (channel <= this._m.inputs) { - this._m.channel = channel; - } else { - console.error("Channel ".concat(channel, " does not exist. Make sure you've provided a value for 'inputs' that is greater than ").concat(channel, " when instantiating the MeydaAnalyzer")); - } - } - /** - * Get a set of features from the current frame. - * @param {(string|Array.)} [features] - * Change the features that Meyda is extracting - * @example - * analyzer.get('spectralFlatness'); - */ + buffer[offset + i - d] |= s * 128 +} - }, { - key: "get", - value: function get(features) { - if (this._m.inputData) { - return this._m.extract(features || this._m._featuresToExtract, this._m.inputData, this._m.previousInputData); - } else { - return null; - } +},{}],91:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) } - }]); - - return MeydaAnalyzer; -}(); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } + } +} -/***/ }), +},{}],92:[function(require,module,exports){ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["Meyda"] = factory(); + else + root["Meyda"] = factory(); +})(window, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); +/******/ }) +/************************************************************************/ +/******/ ({ -/***/ "./src/utilities.js": -/*!**************************!*\ - !*** ./src/utilities.js ***! - \**************************/ -/*! exports provided: isPowerOfTwo, error, pointwiseBufferMult, applyWindow, createBarkScale, typedToArray, arrayToTyped, _normalize, normalize, normalizeToOne, mean, melToFreq, freqToMel, createMelFilterBank, hzToOctaves, normalizeByColumn, createChromaFilterBank, frame */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/***/ "./node_modules/assert/assert.js": +/*!***************************************!*\ + !*** ./node_modules/assert/assert.js ***! + \***************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isPowerOfTwo", function() { return isPowerOfTwo; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "error", function() { return error; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pointwiseBufferMult", function() { return pointwiseBufferMult; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applyWindow", function() { return applyWindow; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createBarkScale", function() { return createBarkScale; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "typedToArray", function() { return typedToArray; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "arrayToTyped", function() { return arrayToTyped; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_normalize", function() { return _normalize; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalizeToOne", function() { return normalizeToOne; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mean", function() { return mean; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "melToFreq", function() { return melToFreq; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "freqToMel", function() { return freqToMel; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createMelFilterBank", function() { return createMelFilterBank; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hzToOctaves", function() { return hzToOctaves; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalizeByColumn", function() { return normalizeByColumn; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createChromaFilterBank", function() { return createChromaFilterBank; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "frame", function() { return frame; }); -/* harmony import */ var _windowing__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./windowing */ "./src/windowing.js"); -function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } +/* WEBPACK VAR INJECTION */(function(global) { -function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } +// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js +// original notice: -function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +function compare(a, b) { + if (a === b) { + return 0; + } -function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } + var x = a.length; + var y = b.length; + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } -var windows = {}; -function isPowerOfTwo(num) { - while (num % 2 === 0 && num > 1) { - num /= 2; + if (x < y) { + return -1; } + if (y < x) { + return 1; + } + return 0; +} +function isBuffer(b) { + if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { + return global.Buffer.isBuffer(b); + } + return !!(b != null && b._isBuffer); +} - return num === 1; +// based on node assert, original notice: + +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +var util = __webpack_require__(/*! util/ */ "./node_modules/webpack-stream/node_modules/util/util.js"); +var hasOwn = Object.prototype.hasOwnProperty; +var pSlice = Array.prototype.slice; +var functionsHaveNames = (function () { + return function foo() {}.name === 'foo'; +}()); +function pToString (obj) { + return Object.prototype.toString.call(obj); } -function error(message) { - throw new Error('Meyda: ' + message); +function isView(arrbuf) { + if (isBuffer(arrbuf)) { + return false; + } + if (typeof global.ArrayBuffer !== 'function') { + return false; + } + if (typeof ArrayBuffer.isView === 'function') { + return ArrayBuffer.isView(arrbuf); + } + if (!arrbuf) { + return false; + } + if (arrbuf instanceof DataView) { + return true; + } + if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { + return true; + } + return false; } -function pointwiseBufferMult(a, b) { - var c = []; +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) - for (var i = 0; i < Math.min(a.length, b.length); i++) { - c[i] = a[i] * b[i]; +var regex = /\s*function\s+([^\(\s]*)\s*/; +// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js +function getName(func) { + if (!util.isFunction(func)) { + return; } - - return c; + if (functionsHaveNames) { + return func.name; + } + var str = func.toString(); + var match = str.match(regex); + return match && match[1]; } -function applyWindow(signal, windowname) { - if (windowname !== 'rect') { - if (windowname === '' || !windowname) windowname = 'hanning'; - if (!windows[windowname]) windows[windowname] = {}; +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; - if (!windows[windowname][signal.length]) { - try { - windows[windowname][signal.length] = _windowing__WEBPACK_IMPORTED_MODULE_0__[windowname](signal.length); - } catch (e) { - throw new Error('Invalid windowing function'); + // try to strip useless frames + var fn_name = getName(stackStartFunction); + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); } - } - signal = pointwiseBufferMult(signal, windows[windowname][signal.length]); + this.stack = out; + } } +}; - return signal; -} -function createBarkScale(length, sampleRate, bufferSize) { - var barkScale = new Float32Array(length); +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); - for (var i = 0; i < barkScale.length; i++) { - barkScale[i] = i * sampleRate / bufferSize; - barkScale[i] = 13 * Math.atan(barkScale[i] / 1315.8) + 3.5 * Math.atan(Math.pow(barkScale[i] / 7518, 2)); +function truncate(s, n) { + if (typeof s === 'string') { + return s.length < n ? s : s.slice(0, n); + } else { + return s; } - - return barkScale; -} -function typedToArray(t) { - // utility to convert typed arrays to normal arrays - return Array.prototype.slice.call(t); -} -function arrayToTyped(t) { - // utility to convert arrays to typed F32 arrays - return Float32Array.from(t); -} -function _normalize(num, range) { - return num / range; -} -function normalize(a, range) { - return a.map(function (n) { - return _normalize(n, range); - }); } -function normalizeToOne(a) { - var max = Math.max.apply(null, a); - return a.map(function (n) { - return n / max; - }); +function inspect(something) { + if (functionsHaveNames || !util.isFunction(something)) { + return util.inspect(something); + } + var rawname = getName(something); + var name = rawname ? ': ' + rawname : ''; + return '[Function' + name + ']'; } -function mean(a) { - return a.reduce(function (prev, cur) { - return prev + cur; - }) / a.length; +function getMessage(self) { + return truncate(inspect(self.actual), 128) + ' ' + + self.operator + ' ' + + truncate(inspect(self.expected), 128); } -function _melToFreq(melValue) { - var freqValue = 700 * (Math.exp(melValue / 1125) - 1); - return freqValue; -} +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. -function _freqToMel(freqValue) { - var melValue = 1125 * Math.log(1 + freqValue / 700); - return melValue; -} +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. -function melToFreq(mV) { - return _melToFreq(mV); -} -function freqToMel(fV) { - return _freqToMel(fV); +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); } -function createMelFilterBank(numFilters, sampleRate, bufferSize) { - //the +2 is the upper and lower limits - var melValues = new Float32Array(numFilters + 2); - var melValuesInFreq = new Float32Array(numFilters + 2); //Generate limits in Hz - from 0 to the nyquist. - - var lowerLimitFreq = 0; - var upperLimitFreq = sampleRate / 2; //Convert the limits to Mel - - var lowerLimitMel = _freqToMel(lowerLimitFreq); - - var upperLimitMel = _freqToMel(upperLimitFreq); //Find the range - - - var range = upperLimitMel - lowerLimitMel; //Find the range as part of the linear interpolation - - var valueToAdd = range / (numFilters + 1); - var fftBinsOfFreq = Array(numFilters + 2); - for (var i = 0; i < melValues.length; i++) { - // Initialising the mel frequencies - // They're a linear interpolation between the lower and upper limits. - melValues[i] = i * valueToAdd; // Convert back to Hz +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; - melValuesInFreq[i] = _melToFreq(melValues[i]); // Find the corresponding bins +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. - fftBinsOfFreq[i] = Math.floor((bufferSize + 1) * melValuesInFreq[i] / sampleRate); - } +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; - var filterBank = Array(numFilters); +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); - for (var j = 0; j < filterBank.length; j++) { - // Create a two dimensional array of size numFilters * (buffersize/2)+1 - // pre-populating the arrays with 0s. - filterBank[j] = Array.apply(null, new Array(bufferSize / 2 + 1)).map(Number.prototype.valueOf, 0); //creating the lower and upper slopes for each bin +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; - for (var _i = fftBinsOfFreq[j]; _i < fftBinsOfFreq[j + 1]; _i++) { - filterBank[j][_i] = (_i - fftBinsOfFreq[j]) / (fftBinsOfFreq[j + 1] - fftBinsOfFreq[j]); - } +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); - for (var _i2 = fftBinsOfFreq[j + 1]; _i2 < fftBinsOfFreq[j + 2]; _i2++) { - filterBank[j][_i2] = (fftBinsOfFreq[j + 2] - _i2) / (fftBinsOfFreq[j + 2] - fftBinsOfFreq[j + 1]); - } +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); } +}; - return filterBank; -} -function hzToOctaves(freq, A440) { - return Math.log2(16 * freq / A440); -} -function normalizeByColumn(a) { - var emptyRow = a[0].map(function () { - return 0; - }); - var colDenominators = a.reduce(function (acc, row) { - row.forEach(function (cell, j) { - acc[j] += Math.pow(cell, 2); - }); - return acc; - }, emptyRow).map(Math.sqrt); - return a.map(function (row, i) { - return row.map(function (v, j) { - return v / (colDenominators[j] || 1); - }); - }); -} -; -function createChromaFilterBank(numFilters, sampleRate, bufferSize) { - var centerOctave = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5; - var octaveWidth = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 2; - var baseC = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; - var A440 = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 440; - var numOutputBins = Math.floor(bufferSize / 2) + 1; - var frequencyBins = new Array(bufferSize).fill(0).map(function (_, i) { - return numFilters * hzToOctaves(sampleRate * i / bufferSize, A440); - }); // Set a value for the 0 Hz bin that is 1.5 octaves below bin 1 - // (so chroma is 50% rotated from bin 1, and bin width is broad) - - frequencyBins[0] = frequencyBins[1] - 1.5 * numFilters; - var binWidthBins = frequencyBins.slice(1).map(function (v, i) { - return Math.max(v - frequencyBins[i]); - }, 1).concat([1]); - var halfNumFilters = Math.round(numFilters / 2); - var filterPeaks = new Array(numFilters).fill(0).map(function (_, i) { - return frequencyBins.map(function (frq) { - return (10 * numFilters + halfNumFilters + frq - i) % numFilters - halfNumFilters; - }); - }); - var weights = filterPeaks.map(function (row, i) { - return row.map(function (_, j) { - return Math.exp(-0.5 * Math.pow(2 * filterPeaks[i][j] / binWidthBins[j], 2)); - }); - }); - weights = normalizeByColumn(weights); - - if (octaveWidth) { - var octaveWeights = frequencyBins.map(function (v) { - return Math.exp(-0.5 * Math.pow((v / numFilters - centerOctave) / octaveWidth, 2)); - }); - weights = weights.map(function (row) { - return row.map(function (cell, j) { - return cell * octaveWeights[j]; - }); - }); - } +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); - if (baseC) { - weights = [].concat(_toConsumableArray(weights.slice(3)), _toConsumableArray(weights.slice(0, 3))); +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); } +}; - return weights.map(function (row) { - return row.slice(0, numOutputBins); - }); -} -function frame(buffer, frameLength, hopLength) { - if (buffer.length < frameLength) { - throw new Error('Buffer is too short for frame length'); +assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); } +}; - if (hopLength < 1) { - throw new Error('Hop length cannot be less that 1'); - } +function _deepEqual(actual, expected, strict, memos) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + } else if (isBuffer(actual) && isBuffer(expected)) { + return compare(actual, expected) === 0; - if (frameLength < 1) { - throw new Error('Frame length cannot be less that 1'); - } + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); - var numFrames = 1 + Math.floor((buffer.length - frameLength) / hopLength); - return new Array(numFrames).fill(0).map(function (_, i) { - return buffer.slice(i * hopLength, i * hopLength + frameLength); - }); -} + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; -/***/ }), + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if ((actual === null || typeof actual !== 'object') && + (expected === null || typeof expected !== 'object')) { + return strict ? actual === expected : actual == expected; -/***/ "./src/windowing.js": -/*!**************************!*\ - !*** ./src/windowing.js ***! - \**************************/ -/*! exports provided: blackman, sine, hanning, hamming */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + // If both values are instances of typed arrays, wrap their underlying + // ArrayBuffers in a Buffer each to increase performance + // This optimization requires the arrays to have the same type as checked by + // Object.prototype.toString (aka pToString). Never perform binary + // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their + // bit patterns are not identical. + } else if (isView(actual) && isView(expected) && + pToString(actual) === pToString(expected) && + !(actual instanceof Float32Array || + actual instanceof Float64Array)) { + return compare(new Uint8Array(actual.buffer), + new Uint8Array(expected.buffer)) === 0; -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "blackman", function() { return blackman; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sine", function() { return sine; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hanning", function() { return hanning; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hamming", function() { return hamming; }); -function blackman(size) { - var blackmanBuffer = new Float32Array(size); - var coeff1 = 2 * Math.PI / (size - 1); - var coeff2 = 2 * coeff1; //According to http://uk.mathworks.com/help/signal/ref/blackman.html - //first half of the window + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else if (isBuffer(actual) !== isBuffer(expected)) { + return false; + } else { + memos = memos || {actual: [], expected: []}; - for (var i = 0; i < size / 2; i++) { - blackmanBuffer[i] = 0.42 - 0.5 * Math.cos(i * coeff1) + 0.08 * Math.cos(i * coeff2); - } //second half of the window + var actualIndex = memos.actual.indexOf(actual); + if (actualIndex !== -1) { + if (actualIndex === memos.expected.indexOf(expected)) { + return true; + } + } + memos.actual.push(actual); + memos.expected.push(expected); - for (var _i = size / 2; _i > 0; _i--) { - blackmanBuffer[size - _i] = blackmanBuffer[_i - 1]; + return objEquiv(actual, expected, strict, memos); } - - return blackmanBuffer; } -function sine(size) { - var coeff = Math.PI / (size - 1); - var sineBuffer = new Float32Array(size); - - for (var i = 0; i < size; i++) { - sineBuffer[i] = Math.sin(coeff * i); - } - return sineBuffer; +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; } -function hanning(size) { - var hanningBuffer = new Float32Array(size); - for (var i = 0; i < size; i++) { - // According to the R documentation - // http://ugrad.stat.ubc.ca/R/library/e1071/html/hanning.window.html - hanningBuffer[i] = 0.5 - 0.5 * Math.cos(2 * Math.PI * i / (size - 1)); +function objEquiv(a, b, strict, actualVisitedObjects) { + if (a === null || a === undefined || b === null || b === undefined) + return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) + return a === b; + if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) + return false; + var aIsArgs = isArguments(a); + var bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b, strict); } - - return hanningBuffer; + var ka = objectKeys(a); + var kb = objectKeys(b); + var key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length !== kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] !== kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) + return false; + } + return true; } -function hamming(size) { - var hammingBuffer = new Float32Array(size); - for (var i = 0; i < size; i++) { - //According to http://uk.mathworks.com/help/signal/ref/hamming.html - hammingBuffer[i] = 0.54 - 0.46 * Math.cos(2 * Math.PI * (i / size - 1)); +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); } +}; - return hammingBuffer; +assert.notDeepStrictEqual = notDeepStrictEqual; +function notDeepStrictEqual(actual, expected, message) { + if (_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); + } } -/***/ }) - -/******/ }); -}); -},{}],85:[function(require,module,exports){ -assert.notEqual = notEqual -assert.notOk = notOk -assert.equal = equal -assert.ok = assert +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); -module.exports = assert +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; -function equal (a, b, m) { - assert(a == b, m) // eslint-disable-line eqeqeq -} +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); -function notEqual (a, b, m) { - assert(a != b, m) // eslint-disable-line eqeqeq -} +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; -function notOk (t, m) { - assert(!t, m) -} +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } -function assert (t, m) { - if (!t) throw new Error(m || 'AssertionError') -} + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } -},{}],86:[function(require,module,exports){ -var splice = require('remove-array-items') -var nanotiming = require('nanotiming') -var assert = require('assert') + try { + if (actual instanceof expected) { + return true; + } + } catch (e) { + // Ignore. The instanceof check doesn't work for arrow functions. + } -module.exports = Nanobus + if (Error.isPrototypeOf(expected)) { + return false; + } -function Nanobus (name) { - if (!(this instanceof Nanobus)) return new Nanobus(name) + return expected.call({}, actual) === true; +} - this._name = name || 'nanobus' - this._starListeners = [] - this._listeners = {} +function _tryBlock(block) { + var error; + try { + block(); + } catch (e) { + error = e; + } + return error; } -Nanobus.prototype.emit = function (eventName) { - assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.emit: eventName should be type string or symbol') +function _throws(shouldThrow, block, expected, message) { + var actual; - var data = [] - for (var i = 1, len = arguments.length; i < len; i++) { - data.push(arguments[i]) + if (typeof block !== 'function') { + throw new TypeError('"block" argument must be a function'); } - var emitTiming = nanotiming(this._name + "('" + eventName.toString() + "')") - var listeners = this._listeners[eventName] - if (listeners && listeners.length > 0) { - this._emit(this._listeners[eventName], data) + if (typeof expected === 'string') { + message = expected; + expected = null; } - if (this._starListeners.length > 0) { - this._emit(this._starListeners, eventName, data, emitTiming.uuid) + actual = _tryBlock(block); + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); } - emitTiming() - return this -} + var userProvidedMessage = typeof message === 'string'; + var isUnwantedException = !shouldThrow && util.isError(actual); + var isUnexpectedException = !shouldThrow && actual && !expected; -Nanobus.prototype.on = Nanobus.prototype.addListener = function (eventName, listener) { - assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.on: eventName should be type string or symbol') - assert.equal(typeof listener, 'function', 'nanobus.on: listener should be type function') + if ((isUnwantedException && + userProvidedMessage && + expectedException(actual, expected)) || + isUnexpectedException) { + fail(actual, expected, 'Got unwanted exception' + message); + } - if (eventName === '*') { - this._starListeners.push(listener) - } else { - if (!this._listeners[eventName]) this._listeners[eventName] = [] - this._listeners[eventName].push(listener) + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; } - return this } -Nanobus.prototype.prependListener = function (eventName, listener) { - assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.prependListener: eventName should be type string or symbol') - assert.equal(typeof listener, 'function', 'nanobus.prependListener: listener should be type function') +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); - if (eventName === '*') { - this._starListeners.unshift(listener) - } else { - if (!this._listeners[eventName]) this._listeners[eventName] = [] - this._listeners[eventName].unshift(listener) - } - return this -} +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws(true, block, error, message); +}; -Nanobus.prototype.once = function (eventName, listener) { - assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.once: eventName should be type string or symbol') - assert.equal(typeof listener, 'function', 'nanobus.once: listener should be type function') +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws(false, block, error, message); +}; - var self = this - this.on(eventName, once) - function once () { - listener.apply(self, arguments) - self.removeListener(eventName, once) +assert.ifError = function(err) { if (err) throw err; }; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); } - return this -} + return keys; +}; -Nanobus.prototype.prependOnceListener = function (eventName, listener) { - assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.prependOnceListener: eventName should be type string or symbol') - assert.equal(typeof listener, 'function', 'nanobus.prependOnceListener: listener should be type function') +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack-stream/node_modules/webpack/buildin/global.js */ "./node_modules/webpack-stream/node_modules/webpack/buildin/global.js"))) - var self = this - this.prependListener(eventName, once) - function once () { - listener.apply(self, arguments) - self.removeListener(eventName, once) - } - return this -} +/***/ }), -Nanobus.prototype.removeListener = function (eventName, listener) { - assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.removeListener: eventName should be type string or symbol') - assert.equal(typeof listener, 'function', 'nanobus.removeListener: listener should be type function') +/***/ "./node_modules/dct/index.js": +/*!***********************************!*\ + !*** ./node_modules/dct/index.js ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - if (eventName === '*') { - this._starListeners = this._starListeners.slice() - return remove(this._starListeners, listener) - } else { - if (typeof this._listeners[eventName] !== 'undefined') { - this._listeners[eventName] = this._listeners[eventName].slice() - } +module.exports = __webpack_require__(/*! ./src/dct.js */ "./node_modules/dct/src/dct.js"); - return remove(this._listeners[eventName], listener) - } - function remove (arr, listener) { - if (!arr) return - var index = arr.indexOf(listener) - if (index !== -1) { - splice(arr, index, 1) - return true - } - } -} +/***/ }), -Nanobus.prototype.removeAllListeners = function (eventName) { - if (eventName) { - if (eventName === '*') { - this._starListeners = [] - } else { - this._listeners[eventName] = [] - } - } else { - this._starListeners = [] - this._listeners = {} - } - return this -} +/***/ "./node_modules/dct/src/dct.js": +/*!*************************************!*\ + !*** ./node_modules/dct/src/dct.js ***! + \*************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { -Nanobus.prototype.listeners = function (eventName) { - var listeners = eventName !== '*' - ? this._listeners[eventName] - : this._starListeners +/*===========================================================================*\ + * Discrete Cosine Transform + * + * (c) Vail Systems. Joshua Jung and Ben Bryan. 2015 + * + * This code is not designed to be highly optimized but as an educational + * tool to understand the Mel-scale and its related coefficients used in + * human speech analysis. +\*===========================================================================*/ +var cosMap = null; - var ret = [] - if (listeners) { - var ilength = listeners.length - for (var i = 0; i < ilength; i++) ret.push(listeners[i]) - } - return ret -} +// Builds a cosine map for the given input size. This allows multiple input sizes to be memoized automagically +// if you want to run the DCT over and over. +var memoizeCosines = function(N) { + cosMap = cosMap || {}; + cosMap[N] = new Array(N*N); -Nanobus.prototype._emit = function (arr, eventName, data, uuid) { - if (typeof arr === 'undefined') return - if (arr.length === 0) return - if (data === undefined) { - data = eventName - eventName = null - } + var PI_N = Math.PI / N; - if (eventName) { - if (uuid !== undefined) { - data = [eventName].concat(data, uuid) - } else { - data = [eventName].concat(data) + for (var k = 0; k < N; k++) { + for (var n = 0; n < N; n++) { + cosMap[N][n + (k * N)] = Math.cos(PI_N * (n + 0.5) * k); } } +}; - var length = arr.length - for (var i = 0; i < length; i++) { - var listener = arr[i] - listener.apply(listener, data) - } -} +function dct(signal, scale) { + var L = signal.length; + scale = scale || 2; -},{"assert":85,"nanotiming":106,"remove-array-items":116}],87:[function(require,module,exports){ -const document = require('global/document') -const nanotiming = require('nanotiming') -const morph = require('nanomorph') -const onload = require('on-load') -const assert = require('assert') + if (!cosMap || !cosMap[L]) memoizeCosines(L); -const OL_KEY_ID = onload.KEY_ID -const OL_ATTR_ID = onload.KEY_ATTR + var coefficients = signal.map(function () {return 0;}); -module.exports = Nanocomponent + return coefficients.map(function (__, ix) { + return scale * signal.reduce(function (prev, cur, ix_, arr) { + return prev + (cur * cosMap[L][ix_ + (ix * L)]); + }, 0); + }); +}; -function makeID () { - return 'ncid-' + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1) -} +module.exports = dct; -Nanocomponent.makeID = makeID -function Nanocomponent (name) { - this._hasWindow = typeof window !== 'undefined' - this._id = null // represents the id of the root node - this._ncID = null // internal nanocomponent id - this._olID = null - this._proxy = null - this._loaded = false // Used to debounce on-load when child-reordering - this._rootNodeName = null - this._name = name || 'nanocomponent' - this._rerender = false +/***/ }), - this._handleLoad = this._handleLoad.bind(this) - this._handleUnload = this._handleUnload.bind(this) +/***/ "./node_modules/fftjs/dist/fft.js": +/*!****************************************!*\ + !*** ./node_modules/fftjs/dist/fft.js ***! + \****************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - this._arguments = [] +"use strict"; - const self = this - Object.defineProperty(this, 'element', { - get: function () { - const el = document.getElementById(self._id) - if (el) return el.dataset.nanocomponent === self._ncID ? el : undefined - } - }) -} +var utils = __webpack_require__(/*! ./utils */ "./node_modules/fftjs/dist/utils.js"); -Nanocomponent.prototype.render = function () { - const renderTiming = nanotiming(this._name + '.render') - const self = this - const args = new Array(arguments.length) - let el +// real to complex fft +var fft = function fft(signal) { - for (let i = 0; i < arguments.length; i++) args[i] = arguments[i] - if (!this._hasWindow) { - const createTiming = nanotiming(this._name + '.create') - el = this.createElement.apply(this, args) - createTiming() - renderTiming() - return el - } else if (this.element) { - el = this.element // retain reference, as the ID might change on render - const updateTiming = nanotiming(this._name + '.update') - const shouldUpdate = this._rerender || this.update.apply(this, args) - updateTiming() - if (this._rerender) this._rerender = false - if (shouldUpdate) { - const desiredHtml = this._handleRender(args) - const morphTiming = nanotiming(this._name + '.morph') - morph(el, desiredHtml) - morphTiming() - if (this.afterupdate) this.afterupdate(el) - } - if (!this._proxy) { this._proxy = this._createProxy() } - renderTiming() - return this._proxy + var complexSignal = {}; + + if (signal.real === undefined || signal.imag === undefined) { + complexSignal = utils.constructComplexArray(signal); } else { - this._reset() - el = this._handleRender(args) - if (this.beforerender) this.beforerender(el) - if (this.load || this.unload || this.afterreorder) { - onload(el, self._handleLoad, self._handleUnload, self._ncID) - this._olID = el.dataset[OL_KEY_ID] - } - renderTiming() - return el + complexSignal.real = signal.real.slice(); + complexSignal.imag = signal.imag.slice(); } -} -Nanocomponent.prototype.rerender = function () { - assert(this.element, 'nanocomponent: cant rerender on an unmounted dom node') - this._rerender = true - this.render.apply(this, this._arguments) -} + var N = complexSignal.real.length; + var logN = Math.log2(N); -Nanocomponent.prototype._handleRender = function (args) { - const createElementTiming = nanotiming(this._name + '.createElement') - const el = this.createElement.apply(this, args) - createElementTiming() - if (!this._rootNodeName) this._rootNodeName = el.nodeName - assert(el instanceof window.Element, 'nanocomponent: createElement should return a single DOM node') - assert(this._rootNodeName === el.nodeName, 'nanocomponent: root node types cannot differ between re-renders') - this._arguments = args - return this._brandNode(this._ensureID(el)) -} + if (Math.round(logN) != logN) throw new Error('Input size must be a power of 2.'); -Nanocomponent.prototype._createProxy = function () { - const proxy = document.createElement(this._rootNodeName) - const self = this - this._brandNode(proxy) - proxy.id = this._id - proxy.setAttribute('data-proxy', '') - proxy.isSameNode = function (el) { - return (el && el.dataset.nanocomponent === self._ncID) + if (complexSignal.real.length != complexSignal.imag.length) { + throw new Error('Real and imaginary components must have the same length.'); } - return proxy -} -Nanocomponent.prototype._reset = function () { - this._ncID = Nanocomponent.makeID() - this._olID = null - this._id = null - this._proxy = null - this._rootNodeName = null -} + var bitReversedIndices = utils.bitReverseArray(N); -Nanocomponent.prototype._brandNode = function (node) { - node.setAttribute('data-nanocomponent', this._ncID) - if (this._olID) node.setAttribute(OL_ATTR_ID, this._olID) - return node -} + // sort array + var ordered = { + 'real': [], + 'imag': [] + }; -Nanocomponent.prototype._ensureID = function (node) { - if (node.id) this._id = node.id - else node.id = this._id = this._ncID - // Update proxy node ID if it changed - if (this._proxy && this._proxy.id !== this._id) this._proxy.id = this._id - return node -} + for (var i = 0; i < N; i++) { + ordered.real[bitReversedIndices[i]] = complexSignal.real[i]; + ordered.imag[bitReversedIndices[i]] = complexSignal.imag[i]; + } -Nanocomponent.prototype._handleLoad = function (el) { - if (this._loaded) { - if (this.afterreorder) this.afterreorder(el) - return // Debounce child-reorders + for (var _i = 0; _i < N; _i++) { + complexSignal.real[_i] = ordered.real[_i]; + complexSignal.imag[_i] = ordered.imag[_i]; } - this._loaded = true - if (this.load) this.load(el) -} + // iterate over the number of stages + for (var n = 1; n <= logN; n++) { + var currN = Math.pow(2, n); -Nanocomponent.prototype._handleUnload = function (el) { - if (this.element) return // Debounce child-reorders - this._loaded = false - if (this.unload) this.unload(el) -} + // find twiddle factors + for (var k = 0; k < currN / 2; k++) { + var twiddle = utils.euler(k, currN); -Nanocomponent.prototype.createElement = function () { - throw new Error('nanocomponent: createElement should be implemented!') -} + // on each block of FT, implement the butterfly diagram + for (var m = 0; m < N / currN; m++) { + var currEvenIndex = currN * m + k; + var currOddIndex = currN * m + k + currN / 2; -Nanocomponent.prototype.update = function () { - throw new Error('nanocomponent: update should be implemented!') -} + var currEvenIndexSample = { + 'real': complexSignal.real[currEvenIndex], + 'imag': complexSignal.imag[currEvenIndex] + }; + var currOddIndexSample = { + 'real': complexSignal.real[currOddIndex], + 'imag': complexSignal.imag[currOddIndex] + }; -},{"assert":88,"global/document":77,"nanomorph":99,"nanotiming":106,"on-load":108}],88:[function(require,module,exports){ -module.exports = assert + var odd = utils.multiply(twiddle, currOddIndexSample); -class AssertionError extends Error {} -AssertionError.prototype.name = 'AssertionError' + var subtractionResult = utils.subtract(currEvenIndexSample, odd); + complexSignal.real[currOddIndex] = subtractionResult.real; + complexSignal.imag[currOddIndex] = subtractionResult.imag; -/** - * Minimal assert function - * @param {any} t Value to check if falsy - * @param {string=} m Optional assertion error message - * @throws {AssertionError} - */ -function assert (t, m) { - if (!t) { - var err = new AssertionError(m) - if (Error.captureStackTrace) Error.captureStackTrace(err, assert) - throw err + var additionResult = utils.add(odd, currEvenIndexSample); + complexSignal.real[currEvenIndex] = additionResult.real; + complexSignal.imag[currEvenIndex] = additionResult.imag; + } + } } -} - -},{}],89:[function(require,module,exports){ -var assert = require('assert') - -var safeExternalLink = /(noopener|noreferrer) (noopener|noreferrer)/ -var protocolLink = /^[\w-_]+:/ -module.exports = href + return complexSignal; +}; -function href (cb, root) { - assert.notEqual(typeof window, 'undefined', 'nanohref: expected window to exist') +// complex to real ifft +var ifft = function ifft(signal) { - root = root || window.document + if (signal.real === undefined || signal.imag === undefined) { + throw new Error("IFFT only accepts a complex input."); + } - assert.equal(typeof cb, 'function', 'nanohref: cb should be type function') - assert.equal(typeof root, 'object', 'nanohref: root should be type object') + var N = signal.real.length; - window.addEventListener('click', function (e) { - if ((e.button && e.button !== 0) || - e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || - e.defaultPrevented) return + var complexSignal = { + 'real': [], + 'imag': [] + }; - var anchor = (function traverse (node) { - if (!node || node === root) return - if (node.localName !== 'a' || node.href === undefined) { - return traverse(node.parentNode) - } - return node - })(e.target) + //take complex conjugate in order to be able to use the regular FFT for IFFT + for (var i = 0; i < N; i++) { + var currentSample = { + 'real': signal.real[i], + 'imag': signal.imag[i] + }; - if (!anchor) return + var conjugateSample = utils.conj(currentSample); + complexSignal.real[i] = conjugateSample.real; + complexSignal.imag[i] = conjugateSample.imag; + } - if (window.location.protocol !== anchor.protocol || - window.location.hostname !== anchor.hostname || - window.location.port !== anchor.port || - anchor.hasAttribute('data-nanohref-ignore') || - anchor.hasAttribute('download') || - (anchor.getAttribute('target') === '_blank' && - safeExternalLink.test(anchor.getAttribute('rel'))) || - protocolLink.test(anchor.getAttribute('href'))) return + //compute + var X = fft(complexSignal); - e.preventDefault() - cb(anchor) - }) -} + //normalize + complexSignal.real = X.real.map(function (val) { + return val / N; + }); -},{"assert":85}],90:[function(require,module,exports){ -'use strict' + complexSignal.imag = X.imag.map(function (val) { + return val / N; + }); -var trailingNewlineRegex = /\n[\s]+$/ -var leadingNewlineRegex = /^\n[\s]+/ -var trailingSpaceRegex = /[\s]+$/ -var leadingSpaceRegex = /^[\s]+/ -var multiSpaceRegex = /[\n\s]+/g + return complexSignal; +}; -var TEXT_TAGS = [ - 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'data', 'dfn', 'em', 'i', - 'kbd', 'mark', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'amp', 'small', 'span', - 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr' -] +module.exports = { + fft: fft, + ifft: ifft +}; -var VERBATIM_TAGS = [ - 'code', 'pre', 'textarea' -] +/***/ }), -module.exports = function appendChild (el, childs) { - if (!Array.isArray(childs)) return +/***/ "./node_modules/fftjs/dist/utils.js": +/*!******************************************!*\ + !*** ./node_modules/fftjs/dist/utils.js ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - var nodeName = el.nodeName.toLowerCase() +"use strict"; - var hadText = false - var value, leader - for (var i = 0, len = childs.length; i < len; i++) { - var node = childs[i] - if (Array.isArray(node)) { - appendChild(el, node) - continue - } +// memoization of the reversal of different lengths. - if (typeof node === 'number' || - typeof node === 'boolean' || - typeof node === 'function' || - node instanceof Date || - node instanceof RegExp) { - node = node.toString() - } +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - var lastChild = el.childNodes[el.childNodes.length - 1] +var memoizedReversal = {}; +var memoizedZeroBuffers = {}; - // Iterate over text nodes - if (typeof node === 'string') { - hadText = true +var constructComplexArray = function constructComplexArray(signal) { + var complexSignal = {}; - // If we already had text, append to the existing text - if (lastChild && lastChild.nodeName === '#text') { - lastChild.nodeValue += node + complexSignal.real = signal.real === undefined ? signal.slice() : signal.real.slice(); - // We didn't have a text node yet, create one - } else { - node = el.ownerDocument.createTextNode(node) - el.appendChild(node) - lastChild = node - } + var bufferSize = complexSignal.real.length; - // If this is the last of the child nodes, make sure we close it out - // right - if (i === len - 1) { - hadText = false - // Trim the child text nodes if the current node isn't a - // node where whitespace matters. - if (TEXT_TAGS.indexOf(nodeName) === -1 && - VERBATIM_TAGS.indexOf(nodeName) === -1) { - value = lastChild.nodeValue - .replace(leadingNewlineRegex, '') - .replace(trailingSpaceRegex, '') - .replace(trailingNewlineRegex, '') - .replace(multiSpaceRegex, ' ') - if (value === '') { - el.removeChild(lastChild) - } else { - lastChild.nodeValue = value - } - } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { - // The very first node in the list should not have leading - // whitespace. Sibling text nodes should have whitespace if there - // was any. - leader = i === 0 ? '' : ' ' - value = lastChild.nodeValue - .replace(leadingNewlineRegex, leader) - .replace(leadingSpaceRegex, ' ') - .replace(trailingSpaceRegex, '') - .replace(trailingNewlineRegex, '') - .replace(multiSpaceRegex, ' ') - lastChild.nodeValue = value - } - } + if (memoizedZeroBuffers[bufferSize] === undefined) { + memoizedZeroBuffers[bufferSize] = Array.apply(null, Array(bufferSize)).map(Number.prototype.valueOf, 0); + } - // Iterate over DOM nodes - } else if (node && node.nodeType) { - // If the last node was a text node, make sure it is properly closed out - if (hadText) { - hadText = false + complexSignal.imag = memoizedZeroBuffers[bufferSize].slice(); - // Trim the child text nodes if the current node isn't a - // text node or a code node - if (TEXT_TAGS.indexOf(nodeName) === -1 && - VERBATIM_TAGS.indexOf(nodeName) === -1) { - value = lastChild.nodeValue - .replace(leadingNewlineRegex, '') - .replace(trailingNewlineRegex, ' ') - .replace(multiSpaceRegex, ' ') + return complexSignal; +}; - // Remove empty text nodes, append otherwise - if (value === '') { - el.removeChild(lastChild) - } else { - lastChild.nodeValue = value - } - // Trim the child nodes but preserve the appropriate whitespace - } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { - value = lastChild.nodeValue - .replace(leadingSpaceRegex, ' ') - .replace(leadingNewlineRegex, '') - .replace(trailingNewlineRegex, ' ') - .replace(multiSpaceRegex, ' ') - lastChild.nodeValue = value - } - } +var bitReverseArray = function bitReverseArray(N) { + if (memoizedReversal[N] === undefined) { + var maxBinaryLength = (N - 1).toString(2).length; //get the binary length of the largest index. + var templateBinary = '0'.repeat(maxBinaryLength); //create a template binary of that length. + var reversed = {}; + for (var n = 0; n < N; n++) { + var currBinary = n.toString(2); //get binary value of current index. - // Store the last nodename - var _nodeName = node.nodeName - if (_nodeName) nodeName = _nodeName.toLowerCase() + //prepend zeros from template to current binary. This makes binary values of all indices have the same length. + currBinary = templateBinary.substr(currBinary.length) + currBinary; - // Append the node to the DOM - el.appendChild(node) + currBinary = [].concat(_toConsumableArray(currBinary)).reverse().join(''); //reverse + reversed[n] = parseInt(currBinary, 2); //convert to decimal } + memoizedReversal[N] = reversed; //save } -} + return memoizedReversal[N]; +}; -},{}],91:[function(require,module,exports){ -'use strict' +// complex multiplication +var multiply = function multiply(a, b) { + return { + 'real': a.real * b.real - a.imag * b.imag, + 'imag': a.real * b.imag + a.imag * b.real + }; +}; -module.exports = [ - 'async', 'autofocus', 'autoplay', 'checked', 'controls', 'default', - 'defaultchecked', 'defer', 'disabled', 'formnovalidate', 'hidden', - 'ismap', 'loop', 'multiple', 'muted', 'novalidate', 'open', 'playsinline', - 'readonly', 'required', 'reversed', 'selected' -] +// complex addition +var add = function add(a, b) { + return { + 'real': a.real + b.real, + 'imag': a.imag + b.imag + }; +}; -},{}],92:[function(require,module,exports){ -module.exports = require('./dom')(document) +// complex subtraction +var subtract = function subtract(a, b) { + return { + 'real': a.real - b.real, + 'imag': a.imag - b.imag + }; +}; -},{"./dom":94}],93:[function(require,module,exports){ -'use strict' +// euler's identity e^x = cos(x) + sin(x) +var euler = function euler(kn, N) { + var x = -2 * Math.PI * kn / N; + return { 'real': Math.cos(x), 'imag': Math.sin(x) }; +}; -module.exports = [ - 'indeterminate' -] +// complex conjugate +var conj = function conj(a) { + a.imag *= -1; + return a; +}; -},{}],94:[function(require,module,exports){ -'use strict' +module.exports = { + bitReverseArray: bitReverseArray, + multiply: multiply, + add: add, + subtract: subtract, + euler: euler, + conj: conj, + constructComplexArray: constructComplexArray +}; -var hyperx = require('hyperx') -var appendChild = require('./append-child') -var SVG_TAGS = require('./svg-tags') -var BOOL_PROPS = require('./bool-props') -// Props that need to be set directly rather than with el.setAttribute() -var DIRECT_PROPS = require('./direct-props') +/***/ }), -var SVGNS = 'http://www.w3.org/2000/svg' -var XLINKNS = 'http://www.w3.org/1999/xlink' +/***/ "./node_modules/inherits/inherits_browser.js": +/*!***************************************************!*\ + !*** ./node_modules/inherits/inherits_browser.js ***! + \***************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { -var COMMENT_TAG = '!--' +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} -module.exports = function (document) { - function nanoHtmlCreateElement (tag, props, children) { - var el - // If an svg tag, it needs a namespace - if (SVG_TAGS.indexOf(tag) !== -1) { - props.namespace = SVGNS - } +/***/ }), - // If we are using a namespace - var ns = false - if (props.namespace) { - ns = props.namespace - delete props.namespace - } +/***/ "./node_modules/process/browser.js": +/*!*****************************************!*\ + !*** ./node_modules/process/browser.js ***! + \*****************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { - // If we are extending a builtin element - var isCustomElement = false - if (props.is) { - isCustomElement = props.is - delete props.is - } +// shim for using process in browser +var process = module.exports = {}; - // Create the element - if (ns) { - if (isCustomElement) { - el = document.createElementNS(ns, tag, { is: isCustomElement }) - } else { - el = document.createElementNS(ns, tag) - } - } else if (tag === COMMENT_TAG) { - return document.createComment(props.comment) - } else if (isCustomElement) { - el = document.createElement(tag, { is: isCustomElement }) - } else { - el = document.createElement(tag) - } +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. - // Create the properties - for (var p in props) { - if (props.hasOwnProperty(p)) { - var key = p.toLowerCase() - var val = props[p] - // Normalize className - if (key === 'classname') { - key = 'class' - p = 'class' - } - // The for attribute gets transformed to htmlFor, but we just set as for - if (p === 'htmlFor') { - p = 'for' - } - // If a property is boolean, set itself to the key - if (BOOL_PROPS.indexOf(key) !== -1) { - if (String(val) === 'true') val = key - else if (String(val) === 'false') continue +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; } - // If a property prefers being set directly vs setAttribute - if (key.slice(0, 2) === 'on' || DIRECT_PROPS.indexOf(key) !== -1) { - el[p] = val + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; } else { - if (ns) { - if (p === 'xlink:href') { - el.setAttributeNS(XLINKNS, p, val) - } else if (/^xmlns($|:)/i.test(p)) { - // skip xmlns definitions - } else { - el.setAttributeNS(null, p, val) - } - } else { - el.setAttribute(p, val) - } + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); } - } } - appendChild(el, children) - return el - } - function createFragment (nodes) { - var fragment = document.createDocumentFragment() - for (var i = 0; i < nodes.length; i++) { - if (nodes[i] == null) continue - if (Array.isArray(nodes[i])) { - fragment.appendChild(createFragment(nodes[i])) - } else { - if (typeof nodes[i] === 'string') nodes[i] = document.createTextNode(nodes[i]) - fragment.appendChild(nodes[i]) - } +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } } - return fragment - } - var exports = hyperx(nanoHtmlCreateElement, { - comments: true, - createFragment: createFragment - }) - exports.default = exports - exports.createComment = nanoHtmlCreateElement - return exports -} -},{"./append-child":90,"./bool-props":91,"./direct-props":93,"./svg-tags":96,"hyperx":80}],95:[function(require,module,exports){ -'use strict' -function nanohtmlRawBrowser (tag) { - var el = document.createElement('div') - el.innerHTML = tag - return toArray(el.childNodes) } +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; -function toArray (arr) { - return Array.isArray(arr) ? arr : [].slice.call(arr) +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } } -module.exports = nanohtmlRawBrowser - -},{}],96:[function(require,module,exports){ -'use strict' - -module.exports = [ - 'svg', 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', - 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', - 'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', - 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', - 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', - 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', - 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', - 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', - 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', - 'font-face-uri', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', - 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', - 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', - 'set', 'stop', 'switch', 'symbol', 'text', 'textPath', 'title', 'tref', - 'tspan', 'use', 'view', 'vkern' -] - -},{}],97:[function(require,module,exports){ -var assert = require('assert') +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; -var emojis = { - trace: '🔍', - debug: '🐛', - info: '✨', - warn: '⚠️', - error: '🚨', - fatal: '💀' + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); } -var levels = { - trace: 10, - debug: 20, - info: 30, - warn: 40, - error: 50, - fatal: 60 -} +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; -var defaultColors = { - foreground: '#d3c0c8', - background: '#2d2d2d', - black: '#2d2d2d', - red: '#f2777a', - green: '#99cc99', - yellow: '#ffcc66', - blue: '#6699cc', - magenta: '#cc99cc', - cyan: '#66cccc', - white: '#d3d0c8', - brightBlack: '#747369' +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; } +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; -module.exports = Nanologger +function noop() {} -function Nanologger (name, opts) { - opts = opts || {} - if (!(this instanceof Nanologger)) return new Nanologger(name, opts) +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; - assert.equal(typeof opts, 'object', 'nanologger: opts should be type object') +process.listeners = function (name) { return [] } - this._name = name || '' - this._colors = Object.assign({}, defaultColors, opts.colors || {}) +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; - try { - this.logLevel = window.localStorage.getItem('logLevel') || 'info' - } catch (e) { - this.logLevel = 'info' - } +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; - this._logLevel = levels[this.logLevel] -} -Nanologger.prototype.trace = function () { - var args = [ 'trace' ] - for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) - this._print.apply(this, args) -} +/***/ }), -Nanologger.prototype.debug = function () { - var args = [ 'debug' ] - for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) - this._print.apply(this, args) -} +/***/ "./node_modules/webpack-stream/node_modules/util/support/isBufferBrowser.js": +/*!**********************************************************************************!*\ + !*** ./node_modules/webpack-stream/node_modules/util/support/isBufferBrowser.js ***! + \**********************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { -Nanologger.prototype.info = function () { - var args = [ 'info' ] - for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) - this._print.apply(this, args) +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; } -Nanologger.prototype.warn = function () { - var args = [ 'warn' ] - for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) - this._print.apply(this, args) -} +/***/ }), -Nanologger.prototype.error = function () { - var args = [ 'error' ] - for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) - this._print.apply(this, args) -} +/***/ "./node_modules/webpack-stream/node_modules/util/util.js": +/*!***************************************************************!*\ + !*** ./node_modules/webpack-stream/node_modules/util/util.js ***! + \***************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { -Nanologger.prototype.fatal = function () { - var args = [ 'fatal' ] - for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) - this._print.apply(this, args) -} +/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. -Nanologger.prototype._print = function (level) { - if (levels[level] < this._logLevel) return +var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || + function getOwnPropertyDescriptors(obj) { + var keys = Object.keys(obj); + var descriptors = {}; + for (var i = 0; i < keys.length; i++) { + descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]); + } + return descriptors; + }; - var time = getTimeStamp() - var emoji = emojis[level] - var name = this._name || 'unknown' +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } - var msgColor = (level === 'error' || level.fatal) - ? this._colors.red - : level === 'warn' - ? this._colors.yellow - : this._colors.green + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; - var objs = [] - var args = [ null ] - var msg = '%c%s ' + emoji + ' %c%s' - args.push(color(this._colors.brightBlack), time) - args.push(color(this._colors.magenta), name) +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + if (typeof process !== 'undefined' && process.noDeprecation === true) { + return fn; + } - for (var i = 1, len = arguments.length; i < len; i++) { - var arg = arguments[i] - if (typeof arg === 'string') { - if (i === 1) { - // first string argument is in color - msg += ' %c%s' - args.push(color(msgColor)) - args.push(arg) - } else if (/ms$/.test(arg)) { - // arguments finishing with 'ms', grey out - msg += ' %c%s' - args.push(color(this._colors.brightBlack)) - args.push(arg) + // Allow for deprecating things in the process of starting up. + if (typeof process === 'undefined') { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); } else { - // normal colors - msg += ' %c%s' - args.push(color(this._colors.white)) - args.push(arg) + console.error(msg); } - } else if (typeof arg === 'number') { - msg += ' %c%d' - args.push(color(this._colors.magenta)) - args.push(arg) - } else { - objs.push(arg) + warned = true; } + return fn.apply(this, arguments); } - args[0] = msg - objs.forEach(function (obj) { - args.push(obj) - }) - - // In IE/Edge console functions don't inherit from Function.prototype - // so this is necessary to get all the args applied. - Function.prototype.apply.apply(console.log, [console, args]) -} - -function color (color) { - return 'color: ' + color + ';' -} + return deprecated; +}; -function getTimeStamp () { - var date = new Date() - var hours = pad(date.getHours().toString()) - var minutes = pad(date.getMinutes().toString()) - var seconds = pad(date.getSeconds().toString()) - return hours + ':' + minutes + ':' + seconds -} -function pad (str) { - return str.length !== 2 ? 0 + str : str -} +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; -},{"assert":125}],98:[function(require,module,exports){ -module.exports = LRU -function LRU (opts) { - if (!(this instanceof LRU)) return new LRU(opts) - if (typeof opts === 'number') opts = {max: opts} - if (!opts) opts = {} - this.cache = {} - this.head = this.tail = null - this.length = 0 - this.max = opts.max || 1000 - this.maxAge = opts.maxAge || 0 +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); } +exports.inspect = inspect; -Object.defineProperty(LRU.prototype, 'keys', { - get: function () { return Object.keys(this.cache) } -}) -LRU.prototype.clear = function () { - this.cache = {} - this.head = this.tail = null - this.length = 0 -} +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; -LRU.prototype.remove = function (key) { - if (typeof key !== 'string') key = '' + key - if (!this.cache.hasOwnProperty(key)) return +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; - var element = this.cache[key] - delete this.cache[key] - this._unlink(key, element.prev, element.next) - return element.value -} -LRU.prototype._unlink = function (key, prev, next) { - this.length-- +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; - if (this.length === 0) { - this.head = this.tail = null + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; } else { - if (this.head === key) { - this.head = prev - this.cache[this.head].next = null - } else if (this.tail === key) { - this.tail = next - this.cache[this.tail].prev = null - } else { - this.cache[prev].next = next - this.cache[next].prev = prev - } + return str; } } -LRU.prototype.peek = function (key) { - if (!this.cache.hasOwnProperty(key)) return - - var element = this.cache[key] - if (!this._checkAge(key, element)) return - return element.value +function stylizeNoColor(str, styleType) { + return str; } -LRU.prototype.set = function (key, value) { - if (typeof key !== 'string') key = '' + key - - var element - - if (this.cache.hasOwnProperty(key)) { - element = this.cache[key] - element.value = value - if (this.maxAge) element.modified = Date.now() - // If it's already the head, there's nothing more to do: - if (key === this.head) return value - this._unlink(key, element.prev, element.next) - } else { - element = {value: value, modified: 0, next: null, prev: null} - if (this.maxAge) element.modified = Date.now() - this.cache[key] = element +function arrayToHash(array) { + var hash = {}; - // Eviction is only possible if the key didn't already exist: - if (this.length === this.max) this.evict() - } + array.forEach(function(val, idx) { + hash[val] = true; + }); - this.length++ - element.next = null - element.prev = this.head + return hash; +} - if (this.head) this.cache[this.head].next = key - this.head = key - if (!this.tail) this.tail = key - return value -} +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } -LRU.prototype._checkAge = function (key, element) { - if (this.maxAge && (Date.now() - element.modified) > this.maxAge) { - this.remove(key) - return false + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; } - return true -} -LRU.prototype.get = function (key) { - if (typeof key !== 'string') key = '' + key - if (!this.cache.hasOwnProperty(key)) return + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); - var element = this.cache[key] + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } - if (!this._checkAge(key, element)) return + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } - if (this.head !== key) { - if (key === this.tail) { - this.tail = element.next - this.cache[this.tail].prev = null - } else { - // Set prev.next -> element.next: - this.cache[element.prev].next = element.next + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); } + } - // Set element.next.prev -> element.prev: - this.cache[element.next].prev = element.prev + var base = '', array = false, braces = ['{', '}']; - // Element is the new head - this.cache[this.head].next = key - element.prev = this.head - element.next = null - this.head = key + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; } - return element.value -} - -LRU.prototype.evict = function () { - if (!this.tail) return - this.remove(this.tail) -} + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } -},{}],99:[function(require,module,exports){ -var assert = require('nanoassert') -var morph = require('./lib/morph') + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } -var TEXT_NODE = 3 -// var DEBUG = false + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } -module.exports = nanomorph + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } -// Morph one tree into another tree -// -// no parent -// -> same: diff and walk children -// -> not same: replace and return -// old node doesn't exist -// -> insert new node -// new node doesn't exist -// -> delete old node -// nodes are not the same -// -> diff nodes and apply patch to old node -// nodes are the same -// -> walk all child nodes and append to old node -function nanomorph (oldTree, newTree, options) { - // if (DEBUG) { - // console.log( - // 'nanomorph\nold\n %s\nnew\n %s', - // oldTree && oldTree.outerHTML, - // newTree && newTree.outerHTML - // ) - // } - assert.equal(typeof oldTree, 'object', 'nanomorph: oldTree should be an object') - assert.equal(typeof newTree, 'object', 'nanomorph: newTree should be an object') + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } - if (options && options.childrenOnly) { - updateChildren(newTree, oldTree) - return oldTree + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } } - assert.notEqual( - newTree.nodeType, - 11, - 'nanomorph: newTree should have one root node (which is not a DocumentFragment)' - ) - - return walk(newTree, oldTree) -} + ctx.seen.push(value); -// Walk and morph a dom tree -function walk (newNode, oldNode) { - // if (DEBUG) { - // console.log( - // 'walk\nold\n %s\nnew\n %s', - // oldNode && oldNode.outerHTML, - // newNode && newNode.outerHTML - // ) - // } - if (!oldNode) { - return newNode - } else if (!newNode) { - return null - } else if (newNode.isSameNode && newNode.isSameNode(oldNode)) { - return oldNode - } else if (newNode.tagName !== oldNode.tagName || getComponentId(newNode) !== getComponentId(oldNode)) { - return newNode + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); } else { - morph(newNode, oldNode) - updateChildren(newNode, oldNode) - return oldNode + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); } -} -function getComponentId (node) { - return node.dataset ? node.dataset.nanomorphComponentId : undefined -} + ctx.seen.pop(); -// Update the children of elements -// (obj, obj) -> null -function updateChildren (newNode, oldNode) { - // if (DEBUG) { - // console.log( - // 'updateChildren\nold\n %s\nnew\n %s', - // oldNode && oldNode.outerHTML, - // newNode && newNode.outerHTML - // ) - // } - var oldChild, newChild, morphed, oldMatch + return reduceToSingleString(output, base, braces); +} - // The offset is only ever increased, and used for [i - offset] in the loop - var offset = 0 - for (var i = 0; ; i++) { - oldChild = oldNode.childNodes[i] - newChild = newNode.childNodes[i - offset] - // if (DEBUG) { - // console.log( - // '===\n- old\n %s\n- new\n %s', - // oldChild && oldChild.outerHTML, - // newChild && newChild.outerHTML - // ) - // } - // Both nodes are empty, do nothing - if (!oldChild && !newChild) { - break +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} - // There is no new child, remove old - } else if (!newChild) { - oldNode.removeChild(oldChild) - i-- - // There is no old child, add new - } else if (!oldChild) { - oldNode.appendChild(newChild) - offset++ +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} - // Both nodes are the same, morph - } else if (same(newChild, oldChild)) { - morphed = walk(newChild, oldChild) - if (morphed !== oldChild) { - oldNode.replaceChild(morphed, oldChild) - offset++ - } - // Both nodes do not share an ID or a placeholder, try reorder +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); } else { - oldMatch = null - - // Try and find a similar node somewhere in the tree - for (var j = i; j < oldNode.childNodes.length; j++) { - if (same(oldNode.childNodes[j], newChild)) { - oldMatch = oldNode.childNodes[j] - break - } - } - - // If there was a node with the same ID or placeholder in the old list - if (oldMatch) { - morphed = walk(newChild, oldMatch) - if (morphed !== oldMatch) offset++ - oldNode.insertBefore(morphed, oldChild) + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} - // It's safe to morph two nodes in-place if neither has an ID - } else if (!newChild.id && !oldChild.id) { - morphed = walk(newChild, oldChild) - if (morphed !== oldChild) { - oldNode.replaceChild(morphed, oldChild) - offset++ - } - // Insert the node at the index if we couldn't morph or find a matching node +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); } else { - oldNode.insertBefore(newChild, oldChild) - offset++ + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); } } -} -function same (a, b) { - if (a.id) return a.id === b.id - if (a.isSameNode) return a.isSameNode(b) - if (a.tagName !== b.tagName) return false - if (a.type === TEXT_NODE) return a.nodeValue === b.nodeValue - return false + return name + ': ' + str; } -},{"./lib/morph":101,"nanoassert":85}],100:[function(require,module,exports){ -module.exports = [ - // attribute events (can be set with attributes) - 'onclick', - 'ondblclick', - 'onmousedown', - 'onmouseup', - 'onmouseover', - 'onmousemove', - 'onmouseout', - 'onmouseenter', - 'onmouseleave', - 'ontouchcancel', - 'ontouchend', - 'ontouchmove', - 'ontouchstart', - 'ondragstart', - 'ondrag', - 'ondragenter', - 'ondragleave', - 'ondragover', - 'ondrop', - 'ondragend', - 'onkeydown', - 'onkeypress', - 'onkeyup', - 'onunload', - 'onabort', - 'onerror', - 'onresize', - 'onscroll', - 'onselect', - 'onchange', - 'onsubmit', - 'onreset', - 'onfocus', - 'onblur', - 'oninput', - 'onanimationend', - 'onanimationiteration', - 'onanimationstart', - // other common events - 'oncontextmenu', - 'onfocusin', - 'onfocusout' -] -},{}],101:[function(require,module,exports){ -var events = require('./events') -var eventsLength = events.length +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); -var ELEMENT_NODE = 1 -var TEXT_NODE = 3 -var COMMENT_NODE = 8 + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } -module.exports = morph + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} -// diff elements and apply the resulting patch to the old node -// (obj, obj) -> null -function morph (newNode, oldNode) { - var nodeType = newNode.nodeType - var nodeName = newNode.nodeName - if (nodeType === ELEMENT_NODE) { - copyAttrs(newNode, oldNode) - } +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; - if (nodeType === TEXT_NODE || nodeType === COMMENT_NODE) { - if (oldNode.nodeValue !== newNode.nodeValue) { - oldNode.nodeValue = newNode.nodeValue - } - } +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; - // Some DOM nodes are weird - // https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js - if (nodeName === 'INPUT') updateInput(newNode, oldNode) - else if (nodeName === 'OPTION') updateOption(newNode, oldNode) - else if (nodeName === 'TEXTAREA') updateTextarea(newNode, oldNode) +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; - copyEvents(newNode, oldNode) +function isNullOrUndefined(arg) { + return arg == null; } +exports.isNullOrUndefined = isNullOrUndefined; -function copyAttrs (newNode, oldNode) { - var oldAttrs = oldNode.attributes - var newAttrs = newNode.attributes - var attrNamespaceURI = null - var attrValue = null - var fromValue = null - var attrName = null - var attr = null +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; - for (var i = newAttrs.length - 1; i >= 0; --i) { - attr = newAttrs[i] - attrName = attr.name - attrNamespaceURI = attr.namespaceURI - attrValue = attr.value - if (attrNamespaceURI) { - attrName = attr.localName || attrName - fromValue = oldNode.getAttributeNS(attrNamespaceURI, attrName) - if (fromValue !== attrValue) { - oldNode.setAttributeNS(attrNamespaceURI, attrName, attrValue) - } - } else { - if (!oldNode.hasAttribute(attrName)) { - oldNode.setAttribute(attrName, attrValue) - } else { - fromValue = oldNode.getAttribute(attrName) - if (fromValue !== attrValue) { - // apparently values are always cast to strings, ah well - if (attrValue === 'null' || attrValue === 'undefined') { - oldNode.removeAttribute(attrName) - } else { - oldNode.setAttribute(attrName, attrValue) - } - } - } - } - } +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; - // Remove any extra attributes found on the original DOM element that - // weren't found on the target element. - for (var j = oldAttrs.length - 1; j >= 0; --j) { - attr = oldAttrs[j] - if (attr.specified !== false) { - attrName = attr.name - attrNamespaceURI = attr.namespaceURI +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; - if (attrNamespaceURI) { - attrName = attr.localName || attrName - if (!newNode.hasAttributeNS(attrNamespaceURI, attrName)) { - oldNode.removeAttributeNS(attrNamespaceURI, attrName) - } - } else { - if (!newNode.hasAttributeNS(null, attrName)) { - oldNode.removeAttribute(attrName) - } - } - } - } +function isUndefined(arg) { + return arg === void 0; } +exports.isUndefined = isUndefined; -function copyEvents (newNode, oldNode) { - for (var i = 0; i < eventsLength; i++) { - var ev = events[i] - if (newNode[ev]) { // if new element has a whitelisted attribute - oldNode[ev] = newNode[ev] // update existing element - } else if (oldNode[ev]) { // if existing element has it and new one doesnt - oldNode[ev] = undefined // remove it from existing element - } - } +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; } +exports.isRegExp = isRegExp; -function updateOption (newNode, oldNode) { - updateAttribute(newNode, oldNode, 'selected') +function isObject(arg) { + return typeof arg === 'object' && arg !== null; } +exports.isObject = isObject; -// The "value" attribute is special for the element since it sets the -// initial value. Changing the "value" attribute without changing the "value" -// property will have no effect since it is only used to the set the initial -// value. Similar for the "checked" attribute, and "disabled". -function updateInput (newNode, oldNode) { - var newValue = newNode.value - var oldValue = oldNode.value +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; - updateAttribute(newNode, oldNode, 'checked') - updateAttribute(newNode, oldNode, 'disabled') +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; - // The "indeterminate" property can not be set using an HTML attribute. - // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox - if (newNode.indeterminate !== oldNode.indeterminate) { - oldNode.indeterminate = newNode.indeterminate - } +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; - // Persist file value since file inputs can't be changed programatically - if (oldNode.type === 'file') return +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; - if (newValue !== oldValue) { - oldNode.setAttribute('value', newValue) - oldNode.value = newValue - } +exports.isBuffer = __webpack_require__(/*! ./support/isBuffer */ "./node_modules/webpack-stream/node_modules/util/support/isBufferBrowser.js"); - if (newValue === 'null') { - oldNode.value = '' - oldNode.removeAttribute('value') - } +function objectToString(o) { + return Object.prototype.toString.call(o); +} - if (!newNode.hasAttributeNS(null, 'value')) { - oldNode.removeAttribute('value') - } else if (oldNode.type === 'range') { - // this is so elements like slider move their UI thingy - oldNode.value = newValue - } + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); } -function updateTextarea (newNode, oldNode) { - var newValue = newNode.value - if (newValue !== oldNode.value) { - oldNode.value = newValue - } - if (oldNode.firstChild && oldNode.firstChild.nodeValue !== newValue) { - // Needed for IE. Apparently IE sets the placeholder as the - // node value and vise versa. This ignores an empty update. - if (newValue === '' && oldNode.firstChild.nodeValue === oldNode.placeholder) { - return - } +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; - oldNode.firstChild.nodeValue = newValue - } +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); } -function updateAttribute (newNode, oldNode, name) { - if (newNode[name] !== oldNode[name]) { - oldNode[name] = newNode[name] - if (newNode[name]) { - oldNode.setAttribute(name, '') - } else { - oldNode.removeAttribute(name) - } + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; } -} + return origin; +}; -},{"./events":100}],102:[function(require,module,exports){ -var reg = /([^?=&]+)(=([^&]*))?/g -var assert = require('assert') +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} -module.exports = qs +var kCustomPromisifiedSymbol = typeof Symbol !== 'undefined' ? Symbol('util.promisify.custom') : undefined; -function qs (url) { - assert.equal(typeof url, 'string', 'nanoquery: url should be type string') +exports.promisify = function promisify(original) { + if (typeof original !== 'function') + throw new TypeError('The "original" argument must be of type Function'); - var obj = {} - url.replace(/^.*\?/, '').replace(reg, function (a0, a1, a2, a3) { - var value = decodeURIComponent(a3) - var key = decodeURIComponent(a1) - if (obj.hasOwnProperty(key)) { - if (Array.isArray(obj[key])) obj[key].push(value) - else obj[key] = [obj[key], value] - } else { - obj[key] = value + if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) { + var fn = original[kCustomPromisifiedSymbol]; + if (typeof fn !== 'function') { + throw new TypeError('The "util.promisify.custom" argument must be of type Function'); } - }) + Object.defineProperty(fn, kCustomPromisifiedSymbol, { + value: fn, enumerable: false, writable: false, configurable: true + }); + return fn; + } - return obj -} + function fn() { + var promiseResolve, promiseReject; + var promise = new Promise(function (resolve, reject) { + promiseResolve = resolve; + promiseReject = reject; + }); -},{"assert":85}],103:[function(require,module,exports){ -'use strict' + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + args.push(function (err, value) { + if (err) { + promiseReject(err); + } else { + promiseResolve(value); + } + }); -var assert = require('assert') + try { + original.apply(this, args); + } catch (err) { + promiseReject(err); + } -module.exports = nanoraf + return promise; + } -// Only call RAF when needed -// (fn, fn?) -> fn -function nanoraf (render, raf) { - assert.equal(typeof render, 'function', 'nanoraf: render should be a function') - assert.ok(typeof raf === 'function' || typeof raf === 'undefined', 'nanoraf: raf should be a function or undefined') + Object.setPrototypeOf(fn, Object.getPrototypeOf(original)); - if (!raf) raf = window.requestAnimationFrame - var redrawScheduled = false - var args = null + if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, { + value: fn, enumerable: false, writable: false, configurable: true + }); + return Object.defineProperties( + fn, + getOwnPropertyDescriptors(original) + ); +} - return function frame () { - if (args === null && !redrawScheduled) { - redrawScheduled = true +exports.promisify.custom = kCustomPromisifiedSymbol - raf(function redraw () { - redrawScheduled = false +function callbackifyOnRejected(reason, cb) { + // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M). + // Because `null` is a special error value in callbacks which means "no error + // occurred", we error-wrap so the callback consumer can distinguish between + // "the promise rejected with null" or "the promise fulfilled with undefined". + if (!reason) { + var newReason = new Error('Promise was rejected with a falsy value'); + newReason.reason = reason; + reason = newReason; + } + return cb(reason); +} - var length = args.length - var _args = new Array(length) - for (var i = 0; i < length; i++) _args[i] = args[i] +function callbackify(original) { + if (typeof original !== 'function') { + throw new TypeError('The "original" argument must be of type Function'); + } - render.apply(render, _args) - args = null - }) + // We DO NOT return the promise as it gives the user a false sense that + // the promise is actually somehow related to the callback's execution + // and that the callback throwing will reject the promise. + function callbackified() { + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); } - args = arguments + var maybeCb = args.pop(); + if (typeof maybeCb !== 'function') { + throw new TypeError('The last argument must be of type Function'); + } + var self = this; + var cb = function() { + return maybeCb.apply(self, arguments); + }; + // In true node style we process the callback on `nextTick` with all the + // implications (stack, `uncaughtException`, `async_hooks`) + original.apply(this, args) + .then(function(ret) { process.nextTick(cb, null, ret) }, + function(rej) { process.nextTick(callbackifyOnRejected, rej, cb) }); } + + Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original)); + Object.defineProperties(callbackified, + getOwnPropertyDescriptors(original)); + return callbackified; } +exports.callbackify = callbackify; -},{"assert":85}],104:[function(require,module,exports){ -var assert = require('assert') -var wayfarer = require('wayfarer') +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../../process/browser.js */ "./node_modules/process/browser.js"))) -// electron support -var isLocalFile = (/file:\/\//.test( - typeof window === 'object' && - window.location && - window.location.origin -)) +/***/ }), -/* eslint-disable no-useless-escape */ -var electron = '^(file:\/\/|\/)(.*\.html?\/?)?' -var protocol = '^(http(s)?(:\/\/))?(www\.)?' -var domain = '[a-zA-Z0-9-_\.]+(:[0-9]{1,5})?(\/{1})?' -var qs = '[\?].*$' -/* eslint-enable no-useless-escape */ +/***/ "./node_modules/webpack-stream/node_modules/webpack/buildin/global.js": +/*!***********************************!*\ + !*** (webpack)/buildin/global.js ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports) { -var stripElectron = new RegExp(electron) -var prefix = new RegExp(protocol + domain) -var normalize = new RegExp('#') -var suffix = new RegExp(qs) +var g; -module.exports = Nanorouter +// This works in non-strict mode +g = (function() { + return this; +})(); -function Nanorouter (opts) { - if (!(this instanceof Nanorouter)) return new Nanorouter(opts) - opts = opts || {} - this.router = wayfarer(opts.default || '/404') +try { + // This works if eval is allowed (see CSP) + g = g || new Function("return this")(); +} catch (e) { + // This works if the window reference is available + if (typeof window === "object") g = window; } -Nanorouter.prototype.on = function (routename, listener) { - assert.equal(typeof routename, 'string') - routename = routename.replace(/^[#/]/, '') - this.router.on(routename, listener) -} +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} -Nanorouter.prototype.emit = function (routename) { - assert.equal(typeof routename, 'string') - routename = pathname(routename, isLocalFile) - return this.router.emit(routename) -} +module.exports = g; -Nanorouter.prototype.match = function (routename) { - assert.equal(typeof routename, 'string') - routename = pathname(routename, isLocalFile) - return this.router.match(routename) -} -// replace everything in a route but the pathname and hash -function pathname (routename, isElectron) { - if (isElectron) routename = routename.replace(stripElectron, '') - else routename = routename.replace(prefix, '') - return decodeURI(routename.replace(suffix, '').replace(normalize, '/')) -} +/***/ }), -},{"assert":85,"wayfarer":123}],105:[function(require,module,exports){ -var assert = require('assert') +/***/ "./src/extractors/chroma.js": +/*!**********************************!*\ + !*** ./src/extractors/chroma.js ***! + \**********************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -var hasWindow = typeof window !== 'undefined' +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } -function createScheduler () { - var scheduler - if (hasWindow) { - if (!window._nanoScheduler) window._nanoScheduler = new NanoScheduler(true) - scheduler = window._nanoScheduler - } else { - scheduler = new NanoScheduler() - } - return scheduler -} +function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } -function NanoScheduler (hasWindow) { - this.hasWindow = hasWindow - this.hasIdle = this.hasWindow && window.requestIdleCallback - this.method = this.hasIdle ? window.requestIdleCallback.bind(window) : this.setTimeout - this.scheduled = false - this.queue = [] -} +function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } -NanoScheduler.prototype.push = function (cb) { - assert.equal(typeof cb, 'function', 'nanoscheduler.push: cb should be type function') +function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } - this.queue.push(cb) - this.schedule() -} +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -NanoScheduler.prototype.schedule = function () { - if (this.scheduled) return +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.ampSpectrum) !== 'object') { + throw new TypeError('Valid ampSpectrum is required to generate chroma'); + } - this.scheduled = true - var self = this - this.method(function (idleDeadline) { - var cb - while (self.queue.length && idleDeadline.timeRemaining() > 0) { - cb = self.queue.shift() - cb(idleDeadline) - } - self.scheduled = false - if (self.queue.length) self.schedule() - }) -} + if (_typeof(args.chromaFilterBank) !== 'object') { + throw new TypeError('Valid chromaFilterBank is required to generate chroma'); + } -NanoScheduler.prototype.setTimeout = function (cb) { - setTimeout(cb, 0, { - timeRemaining: function () { - return 1 - } - }) -} + var chromagram = args.chromaFilterBank.map(function (row, i) { + return args.ampSpectrum.reduce(function (acc, v, j) { + return acc + v * row[j]; + }, 0); + }); + var maxVal = Math.max.apply(Math, _toConsumableArray(chromagram)); + return maxVal ? chromagram.map(function (v) { + return v / maxVal; + }) : chromagram; +}); -module.exports = createScheduler +/***/ }), -},{"assert":85}],106:[function(require,module,exports){ -var scheduler = require('nanoscheduler')() -var assert = require('assert') +/***/ "./src/extractors/energy.js": +/*!**********************************!*\ + !*** ./src/extractors/energy.js ***! + \**********************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -var perf -nanotiming.disabled = true -try { - perf = window.performance - nanotiming.disabled = window.localStorage.DISABLE_NANOTIMING === 'true' || !perf.mark -} catch (e) { } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! assert */ "./node_modules/assert/assert.js"); +/* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(assert__WEBPACK_IMPORTED_MODULE_0__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -module.exports = nanotiming -function nanotiming (name) { - assert.equal(typeof name, 'string', 'nanotiming: name should be type string') +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].signal) !== 'object') { + throw new TypeError(); + } - if (nanotiming.disabled) return noop + var energy = 0; - var uuid = (perf.now() * 10000).toFixed() % Number.MAX_SAFE_INTEGER - var startName = 'start-' + uuid + '-' + name - perf.mark(startName) + for (var i = 0; i < arguments[0].signal.length; i++) { + energy += Math.pow(Math.abs(arguments[0].signal[i]), 2); + } - function end (cb) { - var endName = 'end-' + uuid + '-' + name - perf.mark(endName) + return energy; +}); - scheduler.push(function () { - var err = null - try { - var measureName = name + ' [' + uuid + ']' - perf.measure(measureName, startName, endName) - perf.clearMarks(startName) - perf.clearMarks(endName) - } catch (e) { err = e } - if (cb) cb(err, name) - }) - } +/***/ }), - end.uuid = uuid - return end -} +/***/ "./src/extractors/extractorUtilities.js": +/*!**********************************************!*\ + !*** ./src/extractors/extractorUtilities.js ***! + \**********************************************/ +/*! exports provided: mu */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -function noop (cb) { - if (cb) { - scheduler.push(function () { - cb(new Error('nanotiming: performance API unavailable')) - }) +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mu", function() { return mu; }); +function mu(i, amplitudeSpect) { + var numerator = 0; + var denominator = 0; + + for (var k = 0; k < amplitudeSpect.length; k++) { + numerator += Math.pow(k, i) * Math.abs(amplitudeSpect[k]); + denominator += amplitudeSpect[k]; } -} -},{"assert":85,"nanoscheduler":105}],107:[function(require,module,exports){ -var assert = require('assert') + return numerator / denominator; +} -module.exports = objectChangeCallsite +/***/ }), -function objectChangeCallsite (target, callback) { - assert.equal(typeof target, 'object', 'object-change-callsite: target should be type object') - assert.equal(typeof callback, 'function', 'object-change-callsite: callback should be type function') +/***/ "./src/extractors/loudness.js": +/*!************************************!*\ + !*** ./src/extractors/loudness.js ***! + \************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return new Proxy(target, { - set: function (obj, prop, value) { - var err = new Error() - var trace = strip(err.stack) - callback(prop, value, trace) - obj[prop] = value - return true - }, - deleteProperty: function (target, prop) { - var err = new Error() - var trace = strip(err.stack) - callback(prop, undefined, trace) - if (prop in target) { - delete target[prop] - return true - } - return false - } - }) -} +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -function strip (str) { - var arr = str.split('\n') - arr = arr.length > 2 ? arr.slice(2) : arr - arr[0] = arr[0].replace(/^ {4}at /, '') - return '\n' + arr.join('\n') -} +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.ampSpectrum) !== 'object' || _typeof(args.barkScale) !== 'object') { + throw new TypeError(); + } -},{"assert":125}],108:[function(require,module,exports){ -/* global MutationObserver */ -var document = require('global/document') -var window = require('global/window') -var watch = Object.create(null) -var KEY_ID = 'onloadid' + Math.random().toString(36).slice(2) -var KEY_ATTR = 'data-' + KEY_ID -var INDEX = 0 + var NUM_BARK_BANDS = 24; + var specific = new Float32Array(NUM_BARK_BANDS); + var total = 0; + var normalisedSpectrum = args.ampSpectrum; + var bbLimits = new Int32Array(NUM_BARK_BANDS + 1); + bbLimits[0] = 0; + var currentBandEnd = args.barkScale[normalisedSpectrum.length - 1] / NUM_BARK_BANDS; + var currentBand = 1; -if (window && window.MutationObserver) { - var observer = new MutationObserver(function (mutations) { - if (Object.keys(watch).length < 1) return - for (var i = 0; i < mutations.length; i++) { - if (mutations[i].attributeName === KEY_ATTR) { - eachAttr(mutations[i], turnon, turnoff) - continue - } - eachMutation(mutations[i].removedNodes, function (index, el) { - if (!document.documentElement.contains(el)) turnoff(index, el) - }) - eachMutation(mutations[i].addedNodes, function (index, el) { - if (document.documentElement.contains(el)) turnon(index, el) - }) + for (var i = 0; i < normalisedSpectrum.length; i++) { + while (args.barkScale[i] > currentBandEnd) { + bbLimits[currentBand++] = i; + currentBandEnd = currentBand * args.barkScale[normalisedSpectrum.length - 1] / NUM_BARK_BANDS; } - }) + } - observer.observe(document.documentElement, { - childList: true, - subtree: true, - attributes: true, - attributeOldValue: true, - attributeFilter: [KEY_ATTR] - }) -} + bbLimits[NUM_BARK_BANDS] = normalisedSpectrum.length - 1; //process -module.exports = function onload (el, on, off, caller) { - on = on || function () {} - off = off || function () {} - el.setAttribute(KEY_ATTR, 'o' + INDEX) - watch['o' + INDEX] = [on, off, 0, caller || onload.caller] - INDEX += 1 - return el -} + for (var _i = 0; _i < NUM_BARK_BANDS; _i++) { + var sum = 0; -module.exports.KEY_ATTR = KEY_ATTR -module.exports.KEY_ID = KEY_ID + for (var j = bbLimits[_i]; j < bbLimits[_i + 1]; j++) { + sum += normalisedSpectrum[j]; + } -function turnon (index, el) { - if (watch[index][0] && watch[index][2] === 0) { - watch[index][0](el) - watch[index][2] = 1 - } -} + specific[_i] = Math.pow(sum, 0.23); + } //get total loudness -function turnoff (index, el) { - if (watch[index][1] && watch[index][2] === 1) { - watch[index][1](el) - watch[index][2] = 0 - } -} -function eachAttr (mutation, on, off) { - var newValue = mutation.target.getAttribute(KEY_ATTR) - if (sameOrigin(mutation.oldValue, newValue)) { - watch[newValue] = watch[mutation.oldValue] - return - } - if (watch[mutation.oldValue]) { - off(mutation.oldValue, mutation.target) - } - if (watch[newValue]) { - on(newValue, mutation.target) + for (var _i2 = 0; _i2 < specific.length; _i2++) { + total += specific[_i2]; } -} - -function sameOrigin (oldValue, newValue) { - if (!oldValue || !newValue) return false - return watch[oldValue][3] === watch[newValue][3] -} -function eachMutation (nodes, fn) { - var keys = Object.keys(watch) - for (var i = 0; i < nodes.length; i++) { - if (nodes[i] && nodes[i].getAttribute && nodes[i].getAttribute(KEY_ATTR)) { - var onloadid = nodes[i].getAttribute(KEY_ATTR) - keys.forEach(function (k) { - if (onloadid === k) { - fn(k, nodes[i]) - } - }) - } - if (nodes[i] && nodes[i].childNodes.length > 0) { - eachMutation(nodes[i].childNodes, fn) - } - } -} + return { + specific: specific, + total: total + }; +}); -},{"global/document":77,"global/window":78}],109:[function(require,module,exports){ -var scheduler = require('nanoscheduler')() -var assert = require('assert') +/***/ }), -var entryTypes = [ - 'frame', - 'measure', - 'navigation', - 'resource', - 'longtask' -] +/***/ "./src/extractors/mfcc.js": +/*!********************************!*\ + !*** ./src/extractors/mfcc.js ***! + \********************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -module.exports = onPerformance +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _powerSpectrum__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./powerSpectrum */ "./src/extractors/powerSpectrum.js"); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./../utilities */ "./src/utilities.js"); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -function onPerformance (cb) { - assert.equal(typeof cb, 'function', 'on-performance: cb should be type function') - var PerformanceObserver = typeof window !== 'undefined' && window.PerformanceObserver - if (!PerformanceObserver) return - // Enable singleton. - if (window._onperformance) { - window._onperformance.push(cb) - return stop - } - window._onperformance = [cb] - var observer = new PerformanceObserver(parseEntries) - setTimeout(function () { - parseEntries(window.performance) - observer.observe({ entryTypes: entryTypes }) - }, 0) - return stop +var dct = __webpack_require__(/*! dct */ "./node_modules/dct/index.js"); - function stop () { - window._onperformance.splice(window._onperformance.indexOf(cb), 1) +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.ampSpectrum) !== 'object') { + throw new TypeError('Valid ampSpectrum is required to generate MFCC'); } - function parseEntries (list) { - list.getEntries().forEach(function (entry) { - scheduler.push(function () { - clear(entry) - window._onperformance.forEach(function (cb) { - cb(entry) - }) - }) - }) + if (_typeof(args.melFilterBank) !== 'object') { + throw new TypeError('Valid melFilterBank is required to generate MFCC'); } - // Navigation, longtask and frame don't have a clear method (yet) - // Resource timings can only be cleared in bulk - // see: https://developer.mozilla.org/en-US/docs/Web/API/Performance/clearMeasures - function clear (entry) { - var type = entry.entryType - if (type === 'measure') window.performance.clearMeasures(entry.name) - else if (type === 'resource') window.performance.clearResourceTimings() - } -} + var numberOfMFCCCoefficients = Math.min(40, Math.max(1, args.numberOfMFCCCoefficients || 13)); // Tutorial from: + // http://practicalcryptography.com/miscellaneous/machine-learning + // /guide-mel-frequency-cepstral-coefficients-mfccs/ -},{"assert":85,"nanoscheduler":105}],110:[function(require,module,exports){ -(function (process){ -// Generated by CoffeeScript 1.12.2 -(function() { - var getNanoSeconds, hrtime, loadTime, moduleLoadTime, nodeLoadTime, upTime; + var powSpec = Object(_powerSpectrum__WEBPACK_IMPORTED_MODULE_0__["default"])(args); + var numFilters = args.melFilterBank.length; + var filtered = Array(numFilters); - if ((typeof performance !== "undefined" && performance !== null) && performance.now) { - module.exports = function() { - return performance.now(); - }; - } else if ((typeof process !== "undefined" && process !== null) && process.hrtime) { - module.exports = function() { - return (getNanoSeconds() - nodeLoadTime) / 1e6; - }; - hrtime = process.hrtime; - getNanoSeconds = function() { - var hr; - hr = hrtime(); - return hr[0] * 1e9 + hr[1]; - }; - moduleLoadTime = getNanoSeconds(); - upTime = process.uptime() * 1e9; - nodeLoadTime = moduleLoadTime - upTime; - } else if (Date.now) { - module.exports = function() { - return Date.now() - loadTime; - }; - loadTime = Date.now(); - } else { - module.exports = function() { - return new Date().getTime() - loadTime; - }; - loadTime = new Date().getTime(); + if (numFilters < numberOfMFCCCoefficients) { + throw new Error("Insufficient filter bank for requested number of coefficients"); } -}).call(this); + var loggedMelBands = new Float32Array(numFilters); + for (var i = 0; i < loggedMelBands.length; i++) { + filtered[i] = new Float32Array(args.bufferSize / 2); + loggedMelBands[i] = 0; + for (var j = 0; j < args.bufferSize / 2; j++) { + //point-wise multiplication between power spectrum and filterbanks. + filtered[i][j] = args.melFilterBank[i][j] * powSpec[j]; //summing up all of the coefficients into one array -}).call(this,require('_process')) -},{"_process":135}],111:[function(require,module,exports){ -module.exports = plucker + loggedMelBands[i] += filtered[i][j]; + } //log each coefficient. -function plucker(path, object) { - return arguments.length >= 2 - ? pluck(path)(object) - : pluck(path) -} -function pluck(path) { - path = typeof path === 'string' - ? String(path).trim().split('.') - : path + loggedMelBands[i] = Math.log(loggedMelBands[i] + 1); + } //dct - if (path.length < 2) { - path = path[0] - return pluckSingle - } else { - var l = path.length - return pluckPath - } - function pluckSingle(object) { - return object[path] - } + var loggedMelBandsArray = Array.prototype.slice.call(loggedMelBands); + var mfccs = dct(loggedMelBandsArray).slice(0, numberOfMFCCCoefficients); + return mfccs; +}); - function pluckPath(object) { - for (var i = 0; i < l; i++) { - if (typeof object === 'undefined') break +/***/ }), - object = object[path[i]] - } +/***/ "./src/extractors/perceptualSharpness.js": +/*!***********************************************!*\ + !*** ./src/extractors/perceptualSharpness.js ***! + \***********************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return object - } -} +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _loudness__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./loudness */ "./src/extractors/loudness.js"); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -},{}],112:[function(require,module,exports){ -module.exports = prettierBytes -function prettierBytes (num) { - if (typeof num !== 'number' || isNaN(num)) { - throw new TypeError('Expected a number, got ' + typeof num) +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].signal) !== 'object') { + throw new TypeError(); } - var neg = num < 0 - var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] + var loudnessValue = Object(_loudness__WEBPACK_IMPORTED_MODULE_0__["default"])(arguments[0]); + var spec = loudnessValue.specific; + var output = 0; - if (neg) { - num = -num + for (var i = 0; i < spec.length; i++) { + if (i < 15) { + output += (i + 1) * spec[i + 1]; + } else { + output += 0.066 * Math.exp(0.171 * (i + 1)); + } } - if (num < 1) { - return (neg ? '-' : '') + num + ' B' - } + output *= 0.11 / loudnessValue.total; + return output; +}); - var exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1) - num = Number(num / Math.pow(1000, exponent)) - var unit = units[exponent] +/***/ }), - if (num >= 10 || num % 1 === 0) { - // Do not show decimals when the number is two-digit, or if the number has no - // decimal component. - return (neg ? '-' : '') + num.toFixed(0) + ' ' + unit - } else { - return (neg ? '-' : '') + num.toFixed(1) + ' ' + unit - } -} +/***/ "./src/extractors/perceptualSpread.js": +/*!********************************************!*\ + !*** ./src/extractors/perceptualSpread.js ***! + \********************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -},{}],113:[function(require,module,exports){ -var inherits = require('inherits') -var EventEmitter = require('events').EventEmitter -var now = require('right-now') -var raf = require('raf') +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _loudness__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./loudness */ "./src/extractors/loudness.js"); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -module.exports = Engine -function Engine(fn) { - if (!(this instanceof Engine)) - return new Engine(fn) - this.running = false - this.last = now() - this._frame = 0 - this._tick = this.tick.bind(this) - if (fn) - this.on('tick', fn) -} +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].signal) !== 'object') { + throw new TypeError(); + } -inherits(Engine, EventEmitter) + var loudnessValue = Object(_loudness__WEBPACK_IMPORTED_MODULE_0__["default"])(arguments[0]); + var max = 0; -Engine.prototype.start = function() { - if (this.running) - return - this.running = true - this.last = now() - this._frame = raf(this._tick) - return this -} + for (var i = 0; i < loudnessValue.specific.length; i++) { + if (loudnessValue.specific[i] > max) { + max = loudnessValue.specific[i]; + } + } -Engine.prototype.stop = function() { - this.running = false - if (this._frame !== 0) - raf.cancel(this._frame) - this._frame = 0 - return this -} + var spread = Math.pow((loudnessValue.total - max) / loudnessValue.total, 2); + return spread; +}); -Engine.prototype.tick = function() { - this._frame = raf(this._tick) - var time = now() - var dt = time - this.last - this.emit('tick', dt) - this.last = time -} -},{"events":132,"inherits":83,"raf":114,"right-now":117}],114:[function(require,module,exports){ -(function (global){ -var now = require('performance-now') - , root = typeof window === 'undefined' ? global : window - , vendors = ['moz', 'webkit'] - , suffix = 'AnimationFrame' - , raf = root['request' + suffix] - , caf = root['cancel' + suffix] || root['cancelRequest' + suffix] +/***/ }), -for(var i = 0; !raf && i < vendors.length; i++) { - raf = root[vendors[i] + 'Request' + suffix] - caf = root[vendors[i] + 'Cancel' + suffix] - || root[vendors[i] + 'CancelRequest' + suffix] -} +/***/ "./src/extractors/powerSpectrum.js": +/*!*****************************************!*\ + !*** ./src/extractors/powerSpectrum.js ***! + \*****************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -// Some versions of FF have rAF but not cAF -if(!raf || !caf) { - var last = 0 - , id = 0 - , queue = [] - , frameDuration = 1000 / 60 +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - raf = function(callback) { - if(queue.length === 0) { - var _now = now() - , next = Math.max(0, frameDuration - (_now - last)) - last = next + _now - setTimeout(function() { - var cp = queue.slice(0) - // Clear queue here to prevent - // callbacks from appending listeners - // to the current frame's queue - queue.length = 0 - for(var i = 0; i < cp.length; i++) { - if(!cp[i].cancelled) { - try{ - cp[i].callback(last) - } catch(e) { - setTimeout(function() { throw e }, 0) - } - } - } - }, Math.round(next)) - } - queue.push({ - handle: ++id, - callback: callback, - cancelled: false - }) - return id +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].ampSpectrum) !== 'object') { + throw new TypeError(); } - caf = function(handle) { - for(var i = 0; i < queue.length; i++) { - if(queue[i].handle === handle) { - queue[i].cancelled = true - } - } - } -} + var powerSpectrum = new Float32Array(arguments[0].ampSpectrum.length); -module.exports = function(fn) { - // Wrap in a new function to prevent - // `cancel` potentially being assigned - // to the native rAF function - return raf.call(root, fn) -} -module.exports.cancel = function() { - caf.apply(root, arguments) -} -module.exports.polyfill = function(object) { - if (!object) { - object = root; + for (var i = 0; i < powerSpectrum.length; i++) { + powerSpectrum[i] = Math.pow(arguments[0].ampSpectrum[i], 2); } - object.requestAnimationFrame = raf - object.cancelAnimationFrame = caf -} -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"performance-now":110}],115:[function(require,module,exports){ -(function(U,X){"object"===typeof exports&&"undefined"!==typeof module?module.exports=X():"function"===typeof define&&define.amd?define(X):U.createREGL=X()})(this,function(){function U(a,b){this.id=Eb++;this.type=a;this.data=b}function X(a){if(0===a.length)return[];var b=a.charAt(0),c=a.charAt(a.length-1);if(1>>=b;c=(255>>=c;b|=c;c=(15>>=c;b|=c;c=(3>>c>>1}function hb(){function a(a){a:{for(var b=16;268435456>=b;b*=16)if(a<=b){a=b;break a}a=0}b=c[gb(a)>>2];return 0>2].push(a)}var c=J(8,function(){return[]});return{alloc:a,free:b,allocType:function(b,c){var d=null;switch(b){case 5120:d=new Int8Array(a(c),0,c);break;case 5121:d=new Uint8Array(a(c),0,c);break;case 5122:d=new Int16Array(a(2*c),0,c);break;case 5123:d=new Uint16Array(a(2*c),0,c);break;case 5124:d=new Int32Array(a(4*c),0,c);break;case 5125:d=new Uint32Array(a(4*c),0,c);break;case 5126:d=new Float32Array(a(4*c),0,c);break;default:return null}return d.length!== -c?d.subarray(0,c):d},freeType:function(a){b(a.buffer)}}}function da(a){return!!a&&"object"===typeof a&&Array.isArray(a.shape)&&Array.isArray(a.stride)&&"number"===typeof a.offset&&a.shape.length===a.stride.length&&(Array.isArray(a.data)||M(a.data))}function ib(a,b,c,e,f,d){for(var p=0;pd&&(d=e.buffer.byteLength,5123===m?d>>=1:5125===m&&(d>>=2));e.vertCount=d;d=h;0>h&&(d=4,h=e.buffer.dimension,1===h&&(d=0),2===h&&(d=1),3===h&&(d=4));e.primType=d}function p(a){e.elementsCount--;delete n[a.id];a.buffer.destroy();a.buffer=null}var n={},u=0,t={uint8:5121,uint16:5123};b.oes_element_index_uint&&(t.uint32=5125);f.prototype.bind=function(){this.buffer.bind()};var w=[];return{create:function(a, -b){function l(a){if(a)if("number"===typeof a)h(a),g.primType=4,g.vertCount=a|0,g.type=5121;else{var b=null,c=35044,e=-1,f=-1,k=0,n=0;if(Array.isArray(a)||M(a)||da(a))b=a;else if("data"in a&&(b=a.data),"usage"in a&&(c=ob[a.usage]),"primitive"in a&&(e=Ta[a.primitive]),"count"in a&&(f=a.count|0),"type"in a&&(n=t[a.type]),"length"in a)k=a.length|0;else if(k=f,5123===n||5122===n)k*=2;else if(5125===n||5124===n)k*=4;d(g,b,c,e,f,k,n)}else h(),g.primType=4,g.vertCount=0,g.type=5121;return l}var h=c.create(null, -34963,!0),g=new f(h._buffer);e.elementsCount++;l(a);l._reglType="elements";l._elements=g;l.subdata=function(a,b){h.subdata(a,b);return l};l.destroy=function(){p(g)};return l},createStream:function(a){var b=w.pop();b||(b=new f(c.create(null,34963,!0,!1)._buffer));d(b,a,35040,-1,-1,0,0);return b},destroyStream:function(a){w.push(a)},getElements:function(a){return"function"===typeof a&&a._elements instanceof f?a._elements:null},clear:function(){S(n).forEach(p)}}}function pb(a){for(var b=E.allocType(5123, -a.length),c=0;c>>31<<15,d=(e<<1>>>24)-127,e=e>>13&1023;b[c]=-24>d?f:-14>d?f+(e+1024>>-14-d):15>=e,c.height>>=e,B(c,g[e]),a.mipmask|=1<b;++b)a.images[b]=null;return a}function nb(a){for(var b=a.images,c=0;cb){for(var c=0;c=--this.refCount&&D(this)}});p.profile&&(d.getTotalTextureSize=function(){var a=0;Object.keys(ia).forEach(function(b){a+=ia[b].stats.size});return a});return{create2D:function(b,c){function e(a,b){var c=f.texInfo;Z.call(c);var g=Ha();"number"===typeof a?"number"===typeof b?r(g,a|0,b|0):r(g,a|0,a|0):a?(G(c,a),m(g,a)):r(g,1,1);c.genMipmaps&&(g.mipmask=(g.width<<1)-1);f.mipmask=g.mipmask;u(f, -g);f.internalformat=g.internalformat;e.width=g.width;e.height=g.height;xa(f);z(g,3553);H(c,3553);ya();nb(g);p.profile&&(f.stats.size=Ja(f.internalformat,f.type,g.width,g.height,c.genMipmaps,!1));e.format=aa[f.internalformat];e.type=K[f.type];e.mag=fa[c.magFilter];e.min=Da[c.minFilter];e.wrapS=ua[c.wrapS];e.wrapT=ua[c.wrapT];return e}var f=new O(3553);ia[f.id]=f;d.textureCount++;e(b,c);e.subimage=function(a,b,c,d){b|=0;c|=0;d|=0;var m=h();u(m,f);m.width=0;m.height=0;B(m,a);m.width=m.width||(f.width>> -d)-b;m.height=m.height||(f.height>>d)-c;xa(f);l(m,3553,b,c,d);ya();g(m);return e};e.resize=function(b,c){var g=b|0,d=c|0||g;if(g===f.width&&d===f.height)return e;e.width=f.width=g;e.height=f.height=d;xa(f);for(var h=0;f.mipmask>>h;++h){var m=g>>h,x=d>>h;if(!m||!x)break;a.texImage2D(3553,h,f.format,m,x,0,f.format,f.type,null)}ya();p.profile&&(f.stats.size=Ja(f.internalformat,f.type,g,d,!1,!1));return e};e._reglType="texture2d";e._texture=f;p.profile&&(e.stats=f.stats);e.destroy=function(){f.decRef()}; -return e},createCube:function(b,c,e,f,q,n){function k(a,b,c,g,e,d){var f,ca=y.texInfo;Z.call(ca);for(f=0;6>f;++f)D[f]=Ha();if("number"===typeof a||!a)for(a=a|0||1,f=0;6>f;++f)r(D[f],a,a);else if("object"===typeof a)if(b)m(D[0],a),m(D[1],b),m(D[2],c),m(D[3],g),m(D[4],e),m(D[5],d);else if(G(ca,a),t(y,a),"faces"in a)for(a=a.faces,f=0;6>f;++f)u(D[f],y),m(D[f],a[f]);else for(f=0;6>f;++f)m(D[f],a);u(y,D[0]);y.mipmask=ca.genMipmaps?(D[0].width<<1)-1:D[0].mipmask;y.internalformat=D[0].internalformat;k.width= -D[0].width;k.height=D[0].height;xa(y);for(f=0;6>f;++f)z(D[f],34069+f);H(ca,34067);ya();p.profile&&(y.stats.size=Ja(y.internalformat,y.type,k.width,k.height,ca.genMipmaps,!0));k.format=aa[y.internalformat];k.type=K[y.type];k.mag=fa[ca.magFilter];k.min=Da[ca.minFilter];k.wrapS=ua[ca.wrapS];k.wrapT=ua[ca.wrapT];for(f=0;6>f;++f)nb(D[f]);return k}var y=new O(34067);ia[y.id]=y;d.cubeCount++;var D=Array(6);k(b,c,e,f,q,n);k.subimage=function(a,b,c,e,f){c|=0;e|=0;f|=0;var d=h();u(d,y);d.width=0;d.height=0; -B(d,b);d.width=d.width||(y.width>>f)-c;d.height=d.height||(y.height>>f)-e;xa(y);l(d,34069+a,c,e,f);ya();g(d);return k};k.resize=function(b){b|=0;if(b!==y.width){k.width=y.width=b;k.height=y.height=b;xa(y);for(var c=0;6>c;++c)for(var g=0;y.mipmask>>g;++g)a.texImage2D(34069+c,g,y.format,b>>g,b>>g,0,y.format,y.type,null);ya();p.profile&&(y.stats.size=Ja(y.internalformat,y.type,k.width,k.height,!1,!0));return k}};k._reglType="textureCube";k._texture=y;p.profile&&(k.stats=y.stats);k.destroy=function(){y.decRef()}; -return k},clear:function(){for(var b=0;bc;++c)if(0!==(b.mipmask&1<>c,b.height>>c,0,b.internalformat, -b.type,null);else for(var g=0;6>g;++g)a.texImage2D(34069+g,c,b.internalformat,b.width>>c,b.height>>c,0,b.internalformat,b.type,null);H(b.texInfo,b.target)})},refresh:function(){for(var b=0;bg;++g){for(r= -0;ra;++a)c[a].resize(g);b.width=b.height=g;return b},_reglType:"framebufferCube",destroy:function(){c.forEach(function(a){a.destroy()})}})},clear:function(){S(H).forEach(q)}, -restore:function(){z.cur=null;z.next=null;z.dirty=!0;S(H).forEach(function(b){b.framebuffer=a.createFramebuffer();r(b)})}})}function Za(){this.w=this.z=this.y=this.x=this.state=0;this.buffer=null;this.size=0;this.normalized=!1;this.type=5126;this.divisor=this.stride=this.offset=0}function Sb(a,b,c,e,f){function d(a){if(a!==h.currentVAO){var c=b.oes_vertex_array_object;a?c.bindVertexArrayOES(a.vao):c.bindVertexArrayOES(null);h.currentVAO=a}}function p(c){if(c!==h.currentVAO){if(c)c.bindAttrs();else for(var e= -b.angle_instanced_arrays,f=0;f= -l.byteLength?n.subdata(l):(n.destroy(),c.buffers[d]=null));c.buffers[d]||(n=c.buffers[d]=f.create(h,34962,!1,!0));k.buffer=f.getBuffer(n);k.size=k.buffer.dimension|0;k.normalized=!1;k.type=k.buffer.dtype;k.offset=0;k.stride=0;k.divisor=0;k.state=1;g[d]=1}else f.getBuffer(h)?(k.buffer=f.getBuffer(h),k.size=k.buffer.dimension|0,k.normalized=!1,k.type=k.buffer.dtype,k.offset=0,k.stride=0,k.divisor=0,k.state=1):f.getBuffer(h.buffer)?(k.buffer=f.getBuffer(h.buffer),k.size=(+h.size||k.buffer.dimension)| -0,k.normalized=!!h.normalized||!1,k.type="type"in h?Ia[h.type]:k.buffer.dtype,k.offset=(h.offset||0)|0,k.stride=(h.stride||0)|0,k.divisor=(h.divisor||0)|0,k.state=1):"x"in h&&(k.x=+h.x||0,k.y=+h.y||0,k.z=+h.z||0,k.w=+h.w||0,k.state=2)}for(a=0;aa&&(a=b.stats.uniformsCount)}); -return a},c.getMaxAttributesCount=function(){var a=0;B.forEach(function(b){b.stats.attributesCount>a&&(a=b.stats.attributesCount)});return a});return{clear:function(){var b=a.deleteShader.bind(a);S(t).forEach(b);t={};S(w).forEach(b);w={};B.forEach(function(b){a.deleteProgram(b.program)});B.length=0;k={};c.shaderCount=0},program:function(b,e,d,f){var l=k[e];l||(l=k[e]={});var p=l[b];if(p&&(p.refCount++,!f))return p;var v=new n(e,b);c.shaderCount++;u(v,d,f);p||(l[b]=v);B.push(v);return A(v,{destroy:function(){v.refCount--; -if(0>=v.refCount){a.deleteProgram(v.program);var b=B.indexOf(v);B.splice(b,1);c.shaderCount--}0>=l[v.vertId].refCount&&(a.deleteShader(w[v.vertId]),delete w[v.vertId],delete k[v.fragId][v.vertId]);Object.keys(k[v.fragId]).length||(a.deleteShader(t[v.fragId]),delete t[v.fragId],delete k[v.fragId])}})},restore:function(){t={};w={};for(var a=0;a"+b+"?"+e+".constant["+b+"]:0;"}).join(""),"}}else{", -"if(",x,"(",e,".buffer)){",k,"=",f,".createStream(",34962,",",e,".buffer);","}else{",k,"=",f,".getBuffer(",e,".buffer);","}",l,'="type" in ',e,"?",g.glTypes,"[",e,".type]:",k,".dtype;",h.normalized,"=!!",e,".normalized;");d("size");d("offset");d("stride");d("divisor");c("}}");c.exit("if(",h.isStream,"){",f,".destroyStream(",k,");","}");return h})});return g}function D(a,b){var c=a["static"],d=a.dynamic;if("vao"in c){var e=c.vao;null!==e&&null===t.getVAO(e)&&(e=t.createVAO(e));return v(function(a){return a.link(t.getVAO(e))})}if("vao"in -d){var f=d.vao;return L(f,function(a,b){var c=a.invoke(b,f);return b.def(a.shared.vao+".getVAO("+c+")")})}return null}function y(a){var b=a["static"],c=a.dynamic,d={};Object.keys(b).forEach(function(a){var c=b[a];d[a]=v(function(a,b){return"number"===typeof c||"boolean"===typeof c?""+c:a.link(c)})});Object.keys(c).forEach(function(a){var b=c[a];d[a]=L(b,function(a,c){return a.invoke(c,b)})});return d}function la(a,b,d,e,f){function h(a){var b=m[a];b&&($a[a]=b)}var k=Z(a,b),l=E(a,f),m=F(a,l,f),n=H(a, -f),$a=O(a,f),p=G(a,f,k);h("viewport");h(g("scissor.box"));var q=0>1)",t],");")}function b(){c(w,".drawArraysInstancedANGLE(", -[p,r,q,t],");")}n?B?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")):b()}function g(){function a(){c(k+".drawElements("+[p,q,u,r+"<<(("+u+"-5121)>>1)"]+");")}function b(){c(k+".drawArrays("+[p,r,q]+");")}n?B?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")):b()}var h=a.shared,k=h.gl,l=h.draw,m=d.draw,n=function(){var e=m.elements,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(l,".","elements");e&&f("if("+e+")"+k+".bindBuffer(34963,"+e+".buffer.buffer);");return e}(), -p=e("primitive"),r=e("offset"),q=function(){var e=m.count,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(l,".","count");return e}();if("number"===typeof q){if(0===q)return}else c("if(",q,"){"),c.exit("}");var t,w;oa&&(t=e("instances"),w=a.instancing);var u=n+".type",B=m.elements&&sa(m.elements);oa&&("number"!==typeof t||0<=t)?"string"===typeof t?(c("if(",t,">0){"),f(),c("}else if(",t,"<0){"),g(),c("}")):f():g()}function X(a,b,c,d,e){b=m();e=b.proc("body",e); -oa&&(b.instancing=e.def(b.shared.extensions,".angle_instanced_arrays"));a(b,e,c,d);return b.compile().body}function fa(a,b,c,d){C(a,b);c.useVAO?c.drawVAO?b(a.shared.vao,".setVAO(",c.drawVAO.append(a,b),");"):b(a.shared.vao,".setVAO(",a.shared.vao,".targetVAO);"):(b(a.shared.vao,".setVAO(null);"),U(a,b,c,d.attributes,function(){return!0}));ta(a,b,c,d.uniforms,function(){return!0});aa(a,b,b,c)}function Da(a,b){var c=a.proc("draw",1);C(a,c);V(a,c,b.context);R(a,c,b.framebuffer);T(a,c,b);N(a,c,b.state); -Q(a,c,b,!1,!0);var d=b.shader.progVar.append(a,c);c(a.shared.gl,".useProgram(",d,".program);");if(b.shader.program)fa(a,c,b,b.shader.program);else{c(a.shared.vao,".setVAO(null);");var e=a.global.def("{}"),f=c.def(d,".id"),g=c.def(e,"[",f,"]");c(a.cond(g).then(g,".call(this,a0);")["else"](g,"=",e,"[",f,"]=",a.link(function(c){return X(fa,a,b,c,1)}),"(",d,");",g,".call(this,a0);"))}0=--this.refCount&&p(this)};f.profile&&(e.getTotalRenderbufferSize=function(){var a=0;Object.keys(w).forEach(function(b){a+=w[b].stats.size});return a});return{create:function(b,c){function l(b,c){var d=0,e=0,k=32854; -"object"===typeof b&&b?("shape"in b?(e=b.shape,d=e[0]|0,e=e[1]|0):("radius"in b&&(d=e=b.radius|0),"width"in b&&(d=b.width|0),"height"in b&&(e=b.height|0)),"format"in b&&(k=n[b.format])):"number"===typeof b?(d=b|0,e="number"===typeof c?c|0:d):b||(d=e=1);if(d!==h.width||e!==h.height||k!==h.format)return l.width=h.width=d,l.height=h.height=e,h.format=k,a.bindRenderbuffer(36161,h.renderbuffer),a.renderbufferStorage(36161,k,d,e),f.profile&&(h.stats.size=T[h.format]*h.width*h.height),l.format=u[h.format], -l}var h=new d(a.createRenderbuffer());w[h.id]=h;e.renderbufferCount++;l(b,c);l.resize=function(b,c){var d=b|0,e=c|0||d;if(d===h.width&&e===h.height)return l;l.width=h.width=d;l.height=h.height=e;a.bindRenderbuffer(36161,h.renderbuffer);a.renderbufferStorage(36161,h.format,d,e);f.profile&&(h.stats.size=T[h.format]*h.width*h.height);return l};l._reglType="renderbuffer";l._renderbuffer=h;f.profile&&(l.stats=h.stats);l.destroy=function(){h.decRef()};return l},clear:function(){S(w).forEach(p)},restore:function(){S(w).forEach(function(b){b.renderbuffer= -a.createRenderbuffer();a.bindRenderbuffer(36161,b.renderbuffer);a.renderbufferStorage(36161,b.format,b.width,b.height)});a.bindRenderbuffer(36161,null)}}},Ya=[];Ya[6408]=4;Ya[6407]=3;var Pa=[];Pa[5121]=1;Pa[5126]=4;Pa[36193]=2;var Ba=["x","y","z","w"],Xb="blend.func blend.equation stencil.func stencil.opFront stencil.opBack sample.coverage viewport scissor.box polygonOffset.offset".split(" "),Ea={0:0,1:1,zero:0,one:1,"src color":768,"one minus src color":769,"src alpha":770,"one minus src alpha":771, -"dst color":774,"one minus dst color":775,"dst alpha":772,"one minus dst alpha":773,"constant color":32769,"one minus constant color":32770,"constant alpha":32771,"one minus constant alpha":32772,"src alpha saturate":776},ab={never:512,less:513,"<":513,equal:514,"=":514,"==":514,"===":514,lequal:515,"<=":515,greater:516,">":516,notequal:517,"!=":517,"!==":517,gequal:518,">=":518,always:519},Ra={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056, -invert:5386},Ab={cw:2304,ccw:2305},Bb=new K(!1,!1,!1,function(){}),$b=function(a,b){function c(){this.endQueryIndex=this.startQueryIndex=-1;this.sum=0;this.stats=null}function e(a,b,d){var e=p.pop()||new c;e.startQueryIndex=a;e.endQueryIndex=b;e.sum=0;e.stats=d;n.push(e)}if(!b.ext_disjoint_timer_query)return null;var f=[],d=[],p=[],n=[],u=[],t=[];return{beginQuery:function(a){var c=f.pop()||b.ext_disjoint_timer_query.createQueryEXT();b.ext_disjoint_timer_query.beginQueryEXT(35007,c);d.push(c);e(d.length- -1,d.length,a)},endQuery:function(){b.ext_disjoint_timer_query.endQueryEXT(35007)},pushScopeStats:e,update:function(){var a,c;a=d.length;if(0!==a){t.length=Math.max(t.length,a+1);u.length=Math.max(u.length,a+1);u[0]=0;var e=t[0]=0;for(c=a=0;c=C.length&&e()}var c=Cb(C,a);C[c]=b}}}function t(){var a=Q.viewport,b=Q.scissor_box;a[0]=a[1]=b[0]=b[1]=0;G.viewportWidth=G.framebufferWidth=G.drawingBufferWidth=a[2]=b[2]=l.drawingBufferWidth;G.viewportHeight=G.framebufferHeight=G.drawingBufferHeight=a[3]=b[3]=l.drawingBufferHeight}function w(){G.tick+=1;G.time=v();t();R.procs.poll()}function k(){y.refresh();t();R.procs.refresh();z&&z.update()}function v(){return(Db()- -E)/1E3}a=Ib(a);if(!a)return null;var l=a.gl,h=l.getContextAttributes();l.isContextLost();var g=Jb(l,a);if(!g)return null;var q=Fb(),r={vaoCount:0,bufferCount:0,elementsCount:0,framebufferCount:0,shaderCount:0,textureCount:0,cubeCount:0,renderbufferCount:0,maxTextureUnits:0},m=g.extensions,z=$b(l,m),E=Db(),F=l.drawingBufferWidth,K=l.drawingBufferHeight,G={tick:0,time:0,viewportWidth:F,viewportHeight:K,framebufferWidth:F,framebufferHeight:K,drawingBufferWidth:F,drawingBufferHeight:K,pixelRatio:a.pixelRatio}, -H=Yb(l,m),O=Kb(l,r,a,function(a){return J.destroyBuffer(a)}),J=Sb(l,m,H,r,O),M=Lb(l,m,O,r),D=Tb(l,q,r,a),y=Ob(l,m,H,function(){R.procs.poll()},G,r,a),L=Zb(l,m,H,r,a),V=Rb(l,m,H,y,L,r),R=Wb(l,q,m,H,O,M,y,V,{},J,D,{elements:null,primitive:4,count:-1,offset:0,instances:-1},G,z,a),q=Ub(l,V,R.procs.poll,G,h,m,H),Q=R.next,N=l.canvas,C=[],S=[],T=[],U=[a.onDestroy],aa=null;N&&(N.addEventListener("webglcontextlost",f,!1),N.addEventListener("webglcontextrestored",d,!1));var X=V.setFBO=p({framebuffer:Y.define.call(null, -1,"framebuffer")});k();h=A(p,{clear:function(a){if("framebuffer"in a)if(a.framebuffer&&"framebufferCube"===a.framebuffer_reglType)for(var b=0;6>b;++b)X(A({framebuffer:a.framebuffer.faces[b]},a),n);else X(a,n);else n(null,a)},prop:Y.define.bind(null,1),context:Y.define.bind(null,2),"this":Y.define.bind(null,3),draw:p({}),buffer:function(a){return O.create(a,34962,!1,!1)},elements:function(a){return M.create(a,!1)},texture:y.create2D,cube:y.createCube,renderbuffer:L.create,framebuffer:V.create,framebufferCube:V.createCube, -vao:J.createVAO,attributes:h,frame:u,on:function(a,b){var c;switch(a){case "frame":return u(b);case "lost":c=S;break;case "restore":c=T;break;case "destroy":c=U}c.push(b);return{cancel:function(){for(var a=0;a} arr The target array - * @param {number} startIdx The index to begin removing from (inclusive) - * @param {number} removeCount How many items to remove - */ -module.exports = function removeItems (arr, startIdx, removeCount) { - var i, length = arr.length +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.signal) !== 'object') { + throw new TypeError(); + } - if (startIdx >= length || removeCount === 0) { - return + var rms = 0; + + for (var i = 0; i < args.signal.length; i++) { + rms += Math.pow(args.signal[i], 2); } - removeCount = (startIdx + removeCount > length ? length - startIdx : removeCount) + rms = rms / args.signal.length; + rms = Math.sqrt(rms); + return rms; +}); - var len = length - removeCount +/***/ }), - for (i = startIdx; i < len; ++i) { - arr[i] = arr[i + removeCount] +/***/ "./src/extractors/spectralCentroid.js": +/*!********************************************!*\ + !*** ./src/extractors/spectralCentroid.js ***! + \********************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + + +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].ampSpectrum) !== 'object') { + throw new TypeError(); } - arr.length = len -} + return Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, arguments[0].ampSpectrum); +}); -},{}],117:[function(require,module,exports){ -(function (global){ -module.exports = - global.performance && - global.performance.now ? function now() { - return performance.now() - } : Date.now || function now() { - return +new Date +/***/ }), + +/***/ "./src/extractors/spectralFlatness.js": +/*!********************************************!*\ + !*** ./src/extractors/spectralFlatness.js ***! + \********************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].ampSpectrum) !== 'object') { + throw new TypeError(); } -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],118:[function(require,module,exports){ -module.exports = scrollToAnchor + var numerator = 0; + var denominator = 0; -function scrollToAnchor (anchor, options) { - if (anchor) { - try { - var el = document.querySelector(anchor) - if (el) el.scrollIntoView(options) - } catch (e) {} + for (var i = 0; i < arguments[0].ampSpectrum.length; i++) { + numerator += Math.log(arguments[0].ampSpectrum[i]); + denominator += arguments[0].ampSpectrum[i]; } -} -},{}],119:[function(require,module,exports){ -var fastSafeStringify = require('fast-safe-stringify') -var copy = require('clipboard-copy') + return Math.exp(numerator / arguments[0].ampSpectrum.length) * arguments[0].ampSpectrum.length / denominator; +}); -function tryStringify (obj) { - try { - return JSON.stringify(obj) - } catch (e) {} -} +/***/ }), -function stateCopy (obj) { - var str = tryStringify(obj) || fastSafeStringify(obj) - copy(str) -} +/***/ "./src/extractors/spectralFlux.js": +/*!****************************************!*\ + !*** ./src/extractors/spectralFlux.js ***! + \****************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -module.exports = stateCopy +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -},{"clipboard-copy":73,"fast-safe-stringify":76}],120:[function(require,module,exports){ -var C = "\u037c" -var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C) -var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : Symbol("styleSet") -var top = typeof globalThis != "undefined" ? globalThis : typeof window != "undefined" ? window : {} +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.signal) !== 'object' || _typeof(args.previousSignal) != 'object') { + throw new TypeError(); + } -// :: - Style modules encapsulate a set of CSS rules defined from -// JavaScript. Their definitions are only available in a given DOM -// root after it has been _mounted_ there with `StyleModule.mount`. -// -// Style modules should be created once and stored somewhere, as -// opposed to re-creating them every time you need them. The amount of -// CSS rules generated for a given DOM root is bounded by the amount -// of style modules that were used. So to avoid leaking rules, don't -// create these dynamically, but treat them as one-time allocations. -var StyleModule = exports.StyleModule = function StyleModule(spec, options) { - this.rules = [] - var ref = options || {}; - var finish = ref.finish; + var sf = 0; - function splitSelector(selector) { - return /^@/.test(selector) ? [selector] : selector.split(/,\s*/) + for (var i = -(args.bufferSize / 2); i < signal.length / 2 - 1; i++) { + x = Math.abs(args.signal[i]) - Math.abs(args.previousSignal[i]); + sf += (x + Math.abs(x)) / 2; } - function render(selectors, spec, target, isKeyframes) { - var local = [], isAt = /^@(\w+)\b/.exec(selectors[0]), keyframes = isAt && isAt[1] == "keyframes" - if (isAt && spec == null) { return target.push(selectors[0] + ";") } - for (var prop in spec) { - var value = spec[prop] - if (/&/.test(prop)) { - render(prop.split(/,\s*/).map(function (part) { return selectors.map(function (sel) { return part.replace(/&/, sel); }); }).reduce(function (a, b) { return a.concat(b); }), - value, target) - } else if (value && typeof value == "object") { - if (!isAt) { throw new RangeError("The value of a property (" + prop + ") should be a primitive value.") } - render(splitSelector(prop), value, local, keyframes) - } else if (value != null) { - local.push(prop.replace(/_.*/, "").replace(/[A-Z]/g, function (l) { return "-" + l.toLowerCase(); }) + ": " + value + ";") - } - } - if (local.length || keyframes) { - target.push((finish && !isAt && !isKeyframes ? selectors.map(finish) : selectors).join(", ") + - " {" + local.join(" ") + "}") - } + return sf; +}); + +/***/ }), + +/***/ "./src/extractors/spectralKurtosis.js": +/*!********************************************!*\ + !*** ./src/extractors/spectralKurtosis.js ***! + \********************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + + +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].ampSpectrum) !== 'object') { + throw new TypeError(); } - for (var prop in spec) { render(splitSelector(prop), spec[prop], this.rules) } -}; + var ampspec = arguments[0].ampSpectrum; + var mu1 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, ampspec); + var mu2 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(2, ampspec); + var mu3 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(3, ampspec); + var mu4 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(4, ampspec); + var numerator = -3 * Math.pow(mu1, 4) + 6 * mu1 * mu2 - 4 * mu1 * mu3 + mu4; + var denominator = Math.pow(Math.sqrt(mu2 - Math.pow(mu1, 2)), 4); + return numerator / denominator; +}); -// :: () → string -// Returns a string containing the module's CSS rules. -StyleModule.prototype.getRules = function getRules () { return this.rules.join("\n") }; +/***/ }), -// :: () → string -// Generate a new unique CSS class name. -StyleModule.newName = function newName () { - var id = top[COUNT] || 1 - top[COUNT] = id + 1 - return C + id.toString(36) -}; +/***/ "./src/extractors/spectralRolloff.js": +/*!*******************************************!*\ + !*** ./src/extractors/spectralRolloff.js ***! + \*******************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -// :: (union, union<[StyleModule], StyleModule>) -// -// Mount the given set of modules in the given DOM root, which ensures -// that the CSS rules defined by the module are available in that -// context. -// -// Rules are only added to the document once per root. -// -// Rule order will follow the order of the modules, so that rules from -// modules later in the array take precedence of those from earlier -// modules. If you call this function multiple times for the same root -// in a way that changes the order of already mounted modules, the old -// order will be changed. -StyleModule.mount = function mount (root, modules) { - (root[SET] || new StyleSet(root)).mount(Array.isArray(modules) ? modules : [modules]) -}; +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -var adoptedSet = null +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].ampSpectrum) !== 'object') { + throw new TypeError(); + } -var StyleSet = function StyleSet(root) { - if (!root.head && root.adoptedStyleSheets && typeof CSSStyleSheet != "undefined") { - if (adoptedSet) { - root.adoptedStyleSheets = [adoptedSet.sheet].concat(root.adoptedStyleSheets) - return root[SET] = adoptedSet - } - this.sheet = new CSSStyleSheet - root.adoptedStyleSheets = [this.sheet].concat(root.adoptedStyleSheets) - adoptedSet = this - } else { - this.styleTag = (root.ownerDocument || root).createElement("style") - var target = root.head || root - target.insertBefore(this.styleTag, target.firstChild) + var ampspec = arguments[0].ampSpectrum; //calculate nyquist bin + + var nyqBin = arguments[0].sampleRate / (2 * (ampspec.length - 1)); + var ec = 0; + + for (var i = 0; i < ampspec.length; i++) { + ec += ampspec[i]; } - this.modules = [] - root[SET] = this -}; -StyleSet.prototype.mount = function mount (modules) { - var sheet = this.sheet - var pos = 0 /* Current rule offset */, j = 0 /* Index into this.modules */ - for (var i = 0; i < modules.length; i++) { - var mod = modules[i], index = this.modules.indexOf(mod) - if (index < j && index > -1) { // Ordering conflict - this.modules.splice(index, 1) - j-- - index = -1 - } - if (index == -1) { - this.modules.splice(j++, 0, mod) - if (sheet) { for (var k = 0; k < mod.rules.length; k++) - { sheet.insertRule(mod.rules[k], pos++) } } - } else { - while (j < index) { pos += this.modules[j++].rules.length } - pos += mod.rules.length - j++ - } + var threshold = 0.99 * ec; + var n = ampspec.length - 1; + + while (ec > threshold && n >= 0) { + ec -= ampspec[n]; + --n; } - if (!sheet) { - var text = "" - for (var i$1 = 0; i$1 < this.modules.length; i$1++) - { text += this.modules[i$1].getRules() + "\n" } - this.styleTag.textContent = text + return (n + 1) * nyqBin; +}); + +/***/ }), + +/***/ "./src/extractors/spectralSkewness.js": +/*!********************************************!*\ + !*** ./src/extractors/spectralSkewness.js ***! + \********************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + + +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.ampSpectrum) !== 'object') { + throw new TypeError(); } -}; -// Style::Object> -// -// A style is an object that, in the simple case, maps CSS property -// names to strings holding their values, as in `{color: "red", -// fontWeight: "bold"}`. The property names can be given in -// camel-case—the library will insert a dash before capital letters -// when converting them to CSS. -// -// If you include an underscore in a property name, it and everything -// after it will be removed from the output, which can be useful when -// providing a property multiple times, for browser compatibility -// reasons. -// -// A property in a style object can also be a sub-selector, which -// extends the current context to add a pseudo-selector or a child -// selector. Such a property should contain a `&` character, which -// will be replaced by the current selector. For example `{"&:before": -// {content: '"hi"'}}`. Sub-selectors and regular properties can -// freely be mixed in a given object. Any property containing a `&` is -// assumed to be a sub-selector. -// -// Finally, a property can specify an @-block to be wrapped around the -// styles defined inside the object that's the property's value. For -// example to create a media query you can do `{"@media screen and -// (min-width: 400px)": {...}}`. + var mu1 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, args.ampSpectrum); + var mu2 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(2, args.ampSpectrum); + var mu3 = Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(3, args.ampSpectrum); + var numerator = 2 * Math.pow(mu1, 3) - 3 * mu1 * mu2 + mu3; + var denominator = Math.pow(Math.sqrt(mu2 - Math.pow(mu1, 2)), 3); + return numerator / denominator; +}); +/***/ }), -},{}],121:[function(require,module,exports){ -'use strict'; +/***/ "./src/extractors/spectralSlope.js": +/*!*****************************************!*\ + !*** ./src/extractors/spectralSlope.js ***! + \*****************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -Object.defineProperty(exports, '__esModule', { value: true }); +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } -var base = { - 8: "Backspace", - 9: "Tab", - 10: "Enter", - 12: "NumLock", - 13: "Enter", - 16: "Shift", - 17: "Control", - 18: "Alt", - 20: "CapsLock", - 27: "Escape", - 32: " ", - 33: "PageUp", - 34: "PageDown", - 35: "End", - 36: "Home", - 37: "ArrowLeft", - 38: "ArrowUp", - 39: "ArrowRight", - 40: "ArrowDown", - 44: "PrintScreen", - 45: "Insert", - 46: "Delete", - 59: ";", - 61: "=", - 91: "Meta", - 92: "Meta", - 106: "*", - 107: "+", - 108: ",", - 109: "-", - 110: ".", - 111: "/", - 144: "NumLock", - 145: "ScrollLock", - 160: "Shift", - 161: "Shift", - 162: "Control", - 163: "Control", - 164: "Alt", - 165: "Alt", - 173: "-", - 186: ";", - 187: "=", - 188: ",", - 189: "-", - 190: ".", - 191: "/", - 192: "`", - 219: "[", - 220: "\\", - 221: "]", - 222: "'", - 229: "q" -}; +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.ampSpectrum) !== 'object') { + throw new TypeError(); + } //linear regression + + + var ampSum = 0; + var freqSum = 0; + var freqs = new Float32Array(args.ampSpectrum.length); + var powFreqSum = 0; + var ampFreqSum = 0; + + for (var i = 0; i < args.ampSpectrum.length; i++) { + ampSum += args.ampSpectrum[i]; + var curFreq = i * args.sampleRate / args.bufferSize; + freqs[i] = curFreq; + powFreqSum += curFreq * curFreq; + freqSum += curFreq; + ampFreqSum += curFreq * args.ampSpectrum[i]; + } + + return (args.ampSpectrum.length * ampFreqSum - freqSum * ampSum) / (ampSum * (powFreqSum - Math.pow(freqSum, 2))); +}); + +/***/ }), + +/***/ "./src/extractors/spectralSpread.js": +/*!******************************************!*\ + !*** ./src/extractors/spectralSpread.js ***! + \******************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _extractorUtilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractorUtilities */ "./src/extractors/extractorUtilities.js"); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + + +/* harmony default export */ __webpack_exports__["default"] = (function (args) { + if (_typeof(args.ampSpectrum) !== 'object') { + throw new TypeError(); + } + + return Math.sqrt(Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(2, args.ampSpectrum) - Math.pow(Object(_extractorUtilities__WEBPACK_IMPORTED_MODULE_0__["mu"])(1, args.ampSpectrum), 2)); +}); + +/***/ }), + +/***/ "./src/extractors/zcr.js": +/*!*******************************!*\ + !*** ./src/extractors/zcr.js ***! + \*******************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +/* harmony default export */ __webpack_exports__["default"] = (function () { + if (_typeof(arguments[0].signal) !== 'object') { + throw new TypeError(); + } + + var zcr = 0; + + for (var i = 1; i < arguments[0].signal.length; i++) { + if (arguments[0].signal[i - 1] >= 0 && arguments[0].signal[i] < 0 || arguments[0].signal[i - 1] < 0 && arguments[0].signal[i] >= 0) { + zcr++; + } + } + + return zcr; +}); + +/***/ }), + +/***/ "./src/featureExtractors.js": +/*!**********************************!*\ + !*** ./src/featureExtractors.js ***! + \**********************************/ +/*! exports provided: buffer, rms, energy, complexSpectrum, spectralSlope, spectralCentroid, spectralRolloff, spectralFlatness, spectralSpread, spectralSkewness, spectralKurtosis, amplitudeSpectrum, zcr, loudness, perceptualSpread, perceptualSharpness, powerSpectrum, mfcc, chroma, spectralFlux */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return buffer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "complexSpectrum", function() { return complexSpectrum; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "amplitudeSpectrum", function() { return amplitudeSpectrum; }); +/* harmony import */ var _extractors_rms__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./extractors/rms */ "./src/extractors/rms.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "rms", function() { return _extractors_rms__WEBPACK_IMPORTED_MODULE_0__["default"]; }); + +/* harmony import */ var _extractors_energy__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./extractors/energy */ "./src/extractors/energy.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "energy", function() { return _extractors_energy__WEBPACK_IMPORTED_MODULE_1__["default"]; }); + +/* harmony import */ var _extractors_spectralSlope__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./extractors/spectralSlope */ "./src/extractors/spectralSlope.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralSlope", function() { return _extractors_spectralSlope__WEBPACK_IMPORTED_MODULE_2__["default"]; }); + +/* harmony import */ var _extractors_spectralCentroid__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./extractors/spectralCentroid */ "./src/extractors/spectralCentroid.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralCentroid", function() { return _extractors_spectralCentroid__WEBPACK_IMPORTED_MODULE_3__["default"]; }); + +/* harmony import */ var _extractors_spectralRolloff__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./extractors/spectralRolloff */ "./src/extractors/spectralRolloff.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralRolloff", function() { return _extractors_spectralRolloff__WEBPACK_IMPORTED_MODULE_4__["default"]; }); + +/* harmony import */ var _extractors_spectralFlatness__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./extractors/spectralFlatness */ "./src/extractors/spectralFlatness.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralFlatness", function() { return _extractors_spectralFlatness__WEBPACK_IMPORTED_MODULE_5__["default"]; }); -var shift = { - 48: ")", - 49: "!", - 50: "@", - 51: "#", - 52: "$", - 53: "%", - 54: "^", - 55: "&", - 56: "*", - 57: "(", - 59: ":", - 61: "+", - 173: "_", - 186: ":", - 187: "+", - 188: "<", - 189: "_", - 190: ">", - 191: "?", - 192: "~", - 219: "{", - 220: "|", - 221: "}", - 222: "\"", - 229: "Q" -}; +/* harmony import */ var _extractors_spectralSpread__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./extractors/spectralSpread */ "./src/extractors/spectralSpread.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralSpread", function() { return _extractors_spectralSpread__WEBPACK_IMPORTED_MODULE_6__["default"]; }); -var chrome = typeof navigator != "undefined" && /Chrome\/(\d+)/.exec(navigator.userAgent); -var safari = typeof navigator != "undefined" && /Apple Computer/.test(navigator.vendor); -var gecko = typeof navigator != "undefined" && /Gecko\/\d+/.test(navigator.userAgent); -var mac = typeof navigator != "undefined" && /Mac/.test(navigator.platform); -var ie = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); -var brokenModifierNames = chrome && (mac || +chrome[1] < 57) || gecko && mac; +/* harmony import */ var _extractors_spectralSkewness__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./extractors/spectralSkewness */ "./src/extractors/spectralSkewness.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralSkewness", function() { return _extractors_spectralSkewness__WEBPACK_IMPORTED_MODULE_7__["default"]; }); -// Fill in the digit keys -for (var i = 0; i < 10; i++) base[48 + i] = base[96 + i] = String(i); +/* harmony import */ var _extractors_spectralKurtosis__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./extractors/spectralKurtosis */ "./src/extractors/spectralKurtosis.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralKurtosis", function() { return _extractors_spectralKurtosis__WEBPACK_IMPORTED_MODULE_8__["default"]; }); -// The function keys -for (var i = 1; i <= 24; i++) base[i + 111] = "F" + i; +/* harmony import */ var _extractors_zcr__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./extractors/zcr */ "./src/extractors/zcr.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zcr", function() { return _extractors_zcr__WEBPACK_IMPORTED_MODULE_9__["default"]; }); -// And the alphabetic keys -for (var i = 65; i <= 90; i++) { - base[i] = String.fromCharCode(i + 32); - shift[i] = String.fromCharCode(i); -} +/* harmony import */ var _extractors_loudness__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./extractors/loudness */ "./src/extractors/loudness.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "loudness", function() { return _extractors_loudness__WEBPACK_IMPORTED_MODULE_10__["default"]; }); -// For each code that doesn't have a shift-equivalent, copy the base name -for (var code in base) if (!shift.hasOwnProperty(code)) shift[code] = base[code]; +/* harmony import */ var _extractors_perceptualSpread__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./extractors/perceptualSpread */ "./src/extractors/perceptualSpread.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "perceptualSpread", function() { return _extractors_perceptualSpread__WEBPACK_IMPORTED_MODULE_11__["default"]; }); -function keyName(event) { - // Don't trust event.key in Chrome when there are modifiers until - // they fix https://bugs.chromium.org/p/chromium/issues/detail?id=633838 - var ignoreKey = brokenModifierNames && (event.ctrlKey || event.altKey || event.metaKey) || - (safari || ie) && event.shiftKey && event.key && event.key.length == 1; - var name = (!ignoreKey && event.key) || - (event.shiftKey ? shift : base)[event.keyCode] || - event.key || "Unidentified"; - // Edge sometimes produces wrong names (Issue #3) - if (name == "Esc") name = "Escape"; - if (name == "Del") name = "Delete"; - // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/ - if (name == "Left") name = "ArrowLeft"; - if (name == "Up") name = "ArrowUp"; - if (name == "Right") name = "ArrowRight"; - if (name == "Down") name = "ArrowDown"; - return name -} +/* harmony import */ var _extractors_perceptualSharpness__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./extractors/perceptualSharpness */ "./src/extractors/perceptualSharpness.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "perceptualSharpness", function() { return _extractors_perceptualSharpness__WEBPACK_IMPORTED_MODULE_12__["default"]; }); -exports.base = base; -exports.keyName = keyName; -exports.shift = shift; +/* harmony import */ var _extractors_mfcc__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./extractors/mfcc */ "./src/extractors/mfcc.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mfcc", function() { return _extractors_mfcc__WEBPACK_IMPORTED_MODULE_13__["default"]; }); -},{}],122:[function(require,module,exports){ -/* eslint-disable node/no-deprecated-api */ -var assert = require('assert') +/* harmony import */ var _extractors_chroma__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./extractors/chroma */ "./src/extractors/chroma.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "chroma", function() { return _extractors_chroma__WEBPACK_IMPORTED_MODULE_14__["default"]; }); -module.exports = getAllRoutes +/* harmony import */ var _extractors_powerSpectrum__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./extractors/powerSpectrum */ "./src/extractors/powerSpectrum.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "powerSpectrum", function() { return _extractors_powerSpectrum__WEBPACK_IMPORTED_MODULE_15__["default"]; }); -var transform = function (trie, previous) { - var prev = previous || '/' - var routes = {} - var nodes = trie.nodes - Object.keys(nodes).forEach(function (key) { - var path = (prev === '/' ? prev : prev + '/') + (key === '$$' ? ':' + trie.name : key) - var cb = nodes[key].cb - if (cb !== undefined) { - routes[path] = cb - } - if (Object.keys(nodes[key].nodes).length !== 0) { - var obj = transform(nodes[key], path) - Object.keys(obj).forEach(function (r) { - routes[r] = obj[r] - }) - } - }) - return routes -} +/* harmony import */ var _extractors_spectralFlux__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./extractors/spectralFlux */ "./src/extractors/spectralFlux.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "spectralFlux", function() { return _extractors_spectralFlux__WEBPACK_IMPORTED_MODULE_16__["default"]; }); -// walk a wayfarer trie -// (obj, fn) -> null -function getAllRoutes (router) { - assert.equal(typeof router, 'function', 'wayfarer.getAllRoutes: router should be an function') - var trie = router._trie - assert.equal(typeof trie, 'object', 'wayfarer.getAllRoutes: trie should be an object') - var tree = trie.trie - return transform(tree) -} -},{"assert":85}],123:[function(require,module,exports){ -/* eslint-disable node/no-deprecated-api */ -var assert = require('assert') -var trie = require('./trie') -module.exports = Wayfarer -// create a router -// str -> obj -function Wayfarer (dft) { - if (!(this instanceof Wayfarer)) return new Wayfarer(dft) - var _default = (dft || '').replace(/^\//, '') - var _trie = trie() - emit._trie = _trie - emit.on = on - emit.emit = emit - emit.match = match - emit._wayfarer = true - return emit - // define a route - // (str, fn) -> obj - function on (route, cb) { - assert.equal(typeof route, 'string') - assert.equal(typeof cb, 'function') - route = route || '/' - if (cb._wayfarer && cb._trie) { - _trie.mount(route, cb._trie.trie) - } else { - var node = _trie.create(route) - node.cb = cb - node.route = route - } - return emit - } - // match and call a route - // (str, obj?) -> null - function emit (route) { - var matched = match(route) - var args = new Array(arguments.length) - args[0] = matched.params - for (var i = 1; i < args.length; i++) { - args[i] = arguments[i] - } - return matched.cb.apply(matched.cb, args) - } - function match (route) { - assert.notEqual(route, undefined, "'route' must be defined") - var matched = _trie.match(route) - if (matched && matched.cb) return new Route(matched) - var dft = _trie.match(_default) - if (dft && dft.cb) return new Route(dft) +var buffer = function buffer(args) { + return args.signal; +}; - throw new Error("route '" + route + "' did not match") - } +var complexSpectrum = function complexSpectrum(args) { + return args.complexSpectrum; +}; - function Route (matched) { - this.cb = matched.cb - this.route = matched.route - this.params = matched.params - } -} +var amplitudeSpectrum = function amplitudeSpectrum(args) { + return args.ampSpectrum; +}; -},{"./trie":124,"assert":85}],124:[function(require,module,exports){ -/* eslint-disable node/no-deprecated-api */ -var assert = require('assert') -module.exports = Trie -// create a new trie -// null -> obj -function Trie () { - if (!(this instanceof Trie)) return new Trie() - this.trie = { nodes: {} } -} +/***/ }), -// create a node on the trie at route -// and return a node -// str -> obj -Trie.prototype.create = function (route) { - assert.equal(typeof route, 'string', 'route should be a string') - // strip leading '/' and split routes - var routes = route.replace(/^\//, '').split('/') +/***/ "./src/index.js": +/*!**********************!*\ + !*** ./src/index.js ***! + \**********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - function createNode (index, trie) { - var thisRoute = (has(routes, index) && routes[index]) - if (thisRoute === false) return trie +module.exports = __webpack_require__(/*! ./main */ "./src/main.js")["default"]; - var node = null - if (/^:|^\*/.test(thisRoute)) { - // if node is a name match, set name and append to ':' node - if (!has(trie.nodes, '$$')) { - node = { nodes: {} } - trie.nodes.$$ = node - } else { - node = trie.nodes.$$ - } +/***/ }), - if (thisRoute[0] === '*') { - trie.wildcard = true - } +/***/ "./src/main.js": +/*!*********************!*\ + !*** ./src/main.js ***! + \*********************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - trie.name = thisRoute.replace(/^:|^\*/, '') - } else if (!has(trie.nodes, thisRoute)) { - node = { nodes: {} } - trie.nodes[thisRoute] = node - } else { - node = trie.nodes[thisRoute] - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/utilities.js"); +/* harmony import */ var _featureExtractors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./featureExtractors */ "./src/featureExtractors.js"); +/* harmony import */ var fftjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! fftjs */ "./node_modules/fftjs/dist/fft.js"); +/* harmony import */ var fftjs__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(fftjs__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _meyda_wa__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./meyda-wa */ "./src/meyda-wa.js"); +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - // we must recurse deeper - return createNode(index + 1, node) - } +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - return createNode(0, this.trie) -} -// match a route on the trie -// and return the node -// str -> obj -Trie.prototype.match = function (route) { - assert.equal(typeof route, 'string', 'route should be a string') - var routes = route.replace(/^\//, '').split('/') - var params = {} - function search (index, trie) { - // either there's no match, or we're done searching - if (trie === undefined) return undefined - var thisRoute = routes[index] - if (thisRoute === undefined) return trie - if (has(trie.nodes, thisRoute)) { - // match regular routes first - return search(index + 1, trie.nodes[thisRoute]) - } else if (trie.name) { - // match named routes - try { - params[trie.name] = decodeURIComponent(thisRoute) - } catch (e) { - return search(index, undefined) - } - return search(index + 1, trie.nodes.$$) - } else if (trie.wildcard) { - // match wildcards - try { - params.wildcard = decodeURIComponent(routes.slice(index).join('/')) - } catch (e) { - return search(index, undefined) - } - // return early, or else search may keep recursing through the wildcard - return trie.nodes.$$ - } else { - // no matches found - return search(index + 1) - } - } +/** + * Meyda Module + * @module meyda + */ - var node = search(0, this.trie) +/** + * Options for constructing a MeydaAnalyzer + * @typedef {Object} MeydaOptions + * @property {AudioContext} audioContext - The Audio Context for the MeydaAnalyzer to operate in. + * @property {AudioNode} source - The Audio Node for Meyda to listen to. + * @property {number} [bufferSize] - The size of the buffer. + * @property {number} [hopSize] - The hop size between buffers. + * @property {number} [sampleRate] - The number of samples per second in the audio context. + * @property {Function} [callback] - A function to receive the frames of audio features + * @property {string} [windowingFunction] - The Windowing Function to apply to the signal before transformation to the frequency domain + * @property {string|Array.} [featureExtractors] - Specify the feature extractors you want to run on the audio. + * @property {boolean} [startImmediately] - Pass `true` to start feature extraction immediately + * @property {number} [numberOfMFCCCoefficients] - The number of MFCC co-efficients that the MFCC feature extractor should return + */ - if (!node) return undefined - node = Object.assign({}, node) - node.params = params - return node -} +/** + * Web Audio context + * Either an {@link AudioContext|https://developer.mozilla.org/en-US/docs/Web/API/AudioContext} + * or an {@link OfflineAudioContext|https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext} + * @typedef {Object} AudioContext + */ -// mount a trie onto a node at route -// (str, obj) -> null -Trie.prototype.mount = function (route, trie) { - assert.equal(typeof route, 'string', 'route should be a string') - assert.equal(typeof trie, 'object', 'trie should be a object') +/** + * AudioNode + * A Web AudioNode + * @typedef {Object} AudioNode + */ - var split = route.replace(/^\//, '').split('/') - var node = null - var key = null +/** + * ScriptProcessorNode + * A Web Audio ScriptProcessorNode + * @typedef {Object} ScriptProcessorNode + */ - if (split.length === 1) { - key = split[0] - node = this.create(key) - } else { - var head = split.join('/') - key = split[0] - node = this.create(head) - } +/** + * @class Meyda + * @hideconstructor + * @classdesc + * The schema for the default export of the Meyda library. + * @example + * var Meyda = require('meyda'); + */ - Object.assign(node.nodes, trie.nodes) - if (trie.name) node.name = trie.name +var Meyda = { + /** + * Meyda stores a reference to the relevant audio context here for use inside + * the Web Audio API. + * @instance + * @member {AudioContext} + */ + audioContext: null, - // delegate properties from '/' to the new node - // '/' cannot be reached once mounted - if (node.nodes['']) { - Object.keys(node.nodes['']).forEach(function (key) { - if (key === 'nodes') return - node[key] = node.nodes[''][key] - }) - Object.assign(node.nodes, node.nodes[''].nodes) - delete node.nodes[''].nodes - } -} + /** + * Meyda keeps an internal ScriptProcessorNode in which it runs audio feature + * extraction. The ScriptProcessorNode is stored in this member variable. + * @instance + * @member {ScriptProcessorNode} + */ + spn: null, -function has (object, property) { - return Object.prototype.hasOwnProperty.call(object, property) -} + /** + * The length of each buffer that Meyda will extract audio on. When recieving + * input via the Web Audio API, the Script Processor Node chunks incoming audio + * into arrays of this length. Longer buffers allow for more precision in the + * frequency domain, but increase the amount of time it takes for Meyda to + * output a set of audio features for the buffer. You can calculate how many + * sets of audio features Meyda will output per second by dividing the + * buffer size by the sample rate. If you're using Meyda for visualisation, + * make sure that you're collecting audio features at a rate that's faster + * than or equal to the video frame rate you expect. + * @instance + * @member {number} + */ + bufferSize: 512, + + /** + * The number of samples per second of the incoming audio. This affects + * feature extraction outside of the context of the Web Audio API, and must be + * set accurately - otherwise calculations will be off. + * @instance + * @member {number} + */ + sampleRate: 44100, + + /** + * The number of Mel bands to use in the Mel Frequency Cepstral Co-efficients + * feature extractor + * @instance + * @member {number} + */ + melBands: 26, + + /** + * The number of bands to divide the spectrum into for the Chroma feature + * extractor. 12 is the standard number of semitones per octave in the western + * music tradition, but Meyda can use an arbitrary number of bands, which + * can be useful for microtonal music. + * @instance + * @member {number} + */ + chromaBands: 12, + + /** + * A function you can provide that will be called for each buffer that Meyda + * receives from its source node + * @instance + * @member {Function} + */ + callback: null, + + /** + * Specify the windowing function to apply to the buffer before the + * transformation from the time domain to the frequency domain is performed + * + * The default windowing function is the hanning window. + * + * @instance + * @member {string} + */ + windowingFunction: 'hanning', + + /** + * @member {object} + */ + featureExtractors: _featureExtractors__WEBPACK_IMPORTED_MODULE_1__, + EXTRACTION_STARTED: false, + + /** + * The number of MFCC co-efficients that the MFCC feature extractor should return + * @instance + * @member {number} + */ + numberOfMFCCCoefficients: 13, + _featuresToExtract: [], + windowing: _utilities__WEBPACK_IMPORTED_MODULE_0__["applyWindow"], + _errors: { + notPow2: new Error('Meyda: Buffer size must be a power of 2, e.g. 64 or 512'), + featureUndef: new Error('Meyda: No features defined.'), + invalidFeatureFmt: new Error('Meyda: Invalid feature format'), + invalidInput: new Error('Meyda: Invalid input.'), + noAC: new Error('Meyda: No AudioContext specified.'), + noSource: new Error('Meyda: No source node specified.') + }, + + /** + * @summary + * Create a MeydaAnalyzer + * + * A factory function for creating a MeydaAnalyzer, the interface for using + * Meyda in the context of Web Audio. + * + * @method + * @param {MeydaOptions} options Options - an object containing configuration + * @returns {MeydaAnalyzer} + * @example + * const analyzer = Meyda.createMeydaAnalyzer({ + * "audioContext": audioContext, + * "source": source, + * "bufferSize": 512, + * "featureExtractors": ["rms"], + * "inputs": 2, + * "callback": features => { + * levelRangeElement.value = features.rms; + * } + * }); + */ + createMeydaAnalyzer: function createMeydaAnalyzer(options) { + return new _meyda_wa__WEBPACK_IMPORTED_MODULE_3__["MeydaAnalyzer"](options, Object.assign({}, Meyda)); + }, + + /** + * Extract an audio feature from a buffer + * + * Unless `meyda.windowingFunction` is set otherwise, `extract` will + * internally apply a hanning window to the buffer prior to conversion into + * the frequency domain. + * + * @function + * @param {(string|Array.)} feature - the feature you want to extract + * @param {Array.} signal + * An array of numbers that represents the signal. It should be of length + * `meyda.bufferSize` + * @param {Array.} [previousSignal] - the previous buffer + * @returns {object} Features + * @example + * meyda.bufferSize = 2048; + * const features = meyda.extract(['zcr', 'spectralCentroid'], signal); + */ + extract: function extract(feature, signal, previousSignal) { + var _this = this; -},{"assert":85}],125:[function(require,module,exports){ -(function (global){ -'use strict'; + if (!signal) throw this._errors.invalidInput;else if (_typeof(signal) != 'object') throw this._errors.invalidInput;else if (!feature) throw this._errors.featureUndef;else if (!_utilities__WEBPACK_IMPORTED_MODULE_0__["isPowerOfTwo"](signal.length)) throw this._errors.notPow2; -var objectAssign = require('object-assign'); + if (typeof this.barkScale == 'undefined' || this.barkScale.length != this.bufferSize) { + this.barkScale = _utilities__WEBPACK_IMPORTED_MODULE_0__["createBarkScale"](this.bufferSize, this.sampleRate, this.bufferSize); + } // Recalculate mel bank if buffer length changed -// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js -// original notice: -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -function compare(a, b) { - if (a === b) { - return 0; - } + if (typeof this.melFilterBank == 'undefined' || this.barkScale.length != this.bufferSize || this.melFilterBank.length != this.melBands) { + this.melFilterBank = _utilities__WEBPACK_IMPORTED_MODULE_0__["createMelFilterBank"](Math.max(this.melBands, this.numberOfMFCCCoefficients), this.sampleRate, this.bufferSize); + } // Recalculate chroma bank if buffer length changed - var x = a.length; - var y = b.length; - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i]; - y = b[i]; - break; + if (typeof this.chromaFilterBank == 'undefined' || this.chromaFilterBank.length != this.chromaBands) { + this.chromaFilterBank = _utilities__WEBPACK_IMPORTED_MODULE_0__["createChromaFilterBank"](this.chromaBands, this.sampleRate, this.bufferSize); } - } - - if (x < y) { - return -1; - } - if (y < x) { - return 1; - } - return 0; -} -function isBuffer(b) { - if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { - return global.Buffer.isBuffer(b); - } - return !!(b != null && b._isBuffer); -} - -// based on node assert, original notice: -// NB: The URL to the CommonJS spec is kept just for tradition. -// node-assert has evolved a lot since then, both in API and behavior. - -// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 -// -// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! -// -// Originally from narwhal.js (http://narwhaljs.org) -// Copyright (c) 2009 Thomas Robinson <280north.com> -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the 'Software'), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -var util = require('util/'); -var hasOwn = Object.prototype.hasOwnProperty; -var pSlice = Array.prototype.slice; -var functionsHaveNames = (function () { - return function foo() {}.name === 'foo'; -}()); -function pToString (obj) { - return Object.prototype.toString.call(obj); -} -function isView(arrbuf) { - if (isBuffer(arrbuf)) { - return false; - } - if (typeof global.ArrayBuffer !== 'function') { - return false; - } - if (typeof ArrayBuffer.isView === 'function') { - return ArrayBuffer.isView(arrbuf); - } - if (!arrbuf) { - return false; - } - if (arrbuf instanceof DataView) { - return true; - } - if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { - return true; - } - return false; -} -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. + if (typeof signal.buffer == 'undefined') { + //signal is a normal array, convert to F32A + this.signal = _utilities__WEBPACK_IMPORTED_MODULE_0__["arrayToTyped"](signal); + } else { + this.signal = signal; + } -var assert = module.exports = ok; + var preparedSignal = prepareSignalWithSpectrum(signal, this.windowingFunction, this.bufferSize); + this.signal = preparedSignal.windowedSignal; + this.complexSpectrum = preparedSignal.complexSpectrum; + this.ampSpectrum = preparedSignal.ampSpectrum; -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) + if (previousSignal) { + var _preparedSignal = prepareSignalWithSpectrum(previousSignal, this.windowingFunction, this.bufferSize); -var regex = /\s*function\s+([^\(\s]*)\s*/; -// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js -function getName(func) { - if (!util.isFunction(func)) { - return; - } - if (functionsHaveNames) { - return func.name; - } - var str = func.toString(); - var match = str.match(regex); - return match && match[1]; -} -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - if (options.message) { - this.message = options.message; - this.generatedMessage = false; - } else { - this.message = getMessage(this); - this.generatedMessage = true; - } - var stackStartFunction = options.stackStartFunction || fail; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } else { - // non v8 browsers so we can have a stacktrace - var err = new Error(); - if (err.stack) { - var out = err.stack; + this.previousSignal = _preparedSignal.windowedSignal; + this.previousComplexSpectrum = _preparedSignal.complexSpectrum; + this.previousAmpSpectrum = _preparedSignal.ampSpectrum; + } - // try to strip useless frames - var fn_name = getName(stackStartFunction); - var idx = out.indexOf('\n' + fn_name); - if (idx >= 0) { - // once we have located the function frame - // we need to strip out everything before it (and its line) - var next_line = out.indexOf('\n', idx + 1); - out = out.substring(next_line + 1); - } + var extract = function extract(feature) { + return _this.featureExtractors[feature]({ + ampSpectrum: _this.ampSpectrum, + chromaFilterBank: _this.chromaFilterBank, + complexSpectrum: _this.complexSpectrum, + signal: _this.signal, + bufferSize: _this.bufferSize, + sampleRate: _this.sampleRate, + barkScale: _this.barkScale, + melFilterBank: _this.melFilterBank, + previousSignal: _this.previousSignal, + previousAmpSpectrum: _this.previousAmpSpectrum, + previousComplexSpectrum: _this.previousComplexSpectrum, + numberOfMFCCCoefficients: _this.numberOfMFCCCoefficients + }); + }; - this.stack = out; + if (_typeof(feature) === 'object') { + return feature.reduce(function (acc, el) { + return Object.assign({}, acc, _defineProperty({}, el, extract(el))); + }, {}); + } else if (typeof feature === 'string') { + return extract(feature); + } else { + throw this._errors.invalidFeatureFmt; } } }; -// assert.AssertionError instanceof Error -util.inherits(assert.AssertionError, Error); +var prepareSignalWithSpectrum = function prepareSignalWithSpectrum(signal, windowingFunction, bufferSize) { + var preparedSignal = {}; -function truncate(s, n) { - if (typeof s === 'string') { - return s.length < n ? s : s.slice(0, n); + if (typeof signal.buffer == 'undefined') { + //signal is a normal array, convert to F32A + preparedSignal.signal = _utilities__WEBPACK_IMPORTED_MODULE_0__["arrayToTyped"](signal); } else { - return s; - } -} -function inspect(something) { - if (functionsHaveNames || !util.isFunction(something)) { - return util.inspect(something); + preparedSignal.signal = signal; } - var rawname = getName(something); - var name = rawname ? ': ' + rawname : ''; - return '[Function' + name + ']'; -} -function getMessage(self) { - return truncate(inspect(self.actual), 128) + ' ' + - self.operator + ' ' + - truncate(inspect(self.expected), 128); -} -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. + preparedSignal.windowedSignal = _utilities__WEBPACK_IMPORTED_MODULE_0__["applyWindow"](preparedSignal.signal, windowingFunction); + preparedSignal.complexSpectrum = Object(fftjs__WEBPACK_IMPORTED_MODULE_2__["fft"])(preparedSignal.windowedSignal); + preparedSignal.ampSpectrum = new Float32Array(bufferSize / 2); -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. + for (var i = 0; i < bufferSize / 2; i++) { + preparedSignal.ampSpectrum[i] = Math.sqrt(Math.pow(preparedSignal.complexSpectrum.real[i], 2) + Math.pow(preparedSignal.complexSpectrum.imag[i], 2)); + } -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} + return preparedSignal; +}; +/** + * The Meyda class + * @type {Meyda} + */ -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, !!guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. +/* harmony default export */ __webpack_exports__["default"] = (Meyda); +if (typeof window !== 'undefined') window.Meyda = Meyda; -function ok(value, message) { - if (!value) fail(value, true, message, '==', assert.ok); -} -assert.ok = ok; +/***/ }), -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); +/***/ "./src/meyda-wa.js": +/*!*************************!*\ + !*** ./src/meyda-wa.js ***! + \*************************/ +/*! exports provided: MeydaAnalyzer */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); -}; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeydaAnalyzer", function() { return MeydaAnalyzer; }); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/utilities.js"); +/* harmony import */ var _featureExtractors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./featureExtractors */ "./src/featureExtractors.js"); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); - } -}; +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); - } -}; -assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); - } -}; +/** + * MeydaAnalyzer + * @classdesc + * Meyda's interface to the Web Audio API. MeydaAnalyzer abstracts an API on + * top of the Web Audio API's ScriptProcessorNode, running the Meyda audio + * feature extractors inside that context. + * + * MeydaAnalyzer's constructor should not be called directly - MeydaAnalyzer + * objects should be generated using the {@link Meyda.createMeydaAnalyzer} + * factory function in the main Meyda class. + * + * @example + * const analyzer = Meyda.createMeydaAnalyzer({ + * "audioContext": audioContext, + * "source": source, + * "bufferSize": 512, + * "featureExtractors": ["rms"], + * "inputs": 2, + * "numberOfMFCCCoefficients": 20 + * "callback": features => { + * levelRangeElement.value = features.rms; + * } + * }); + * @hideconstructor + */ -function _deepEqual(actual, expected, strict, memos) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - } else if (isBuffer(actual) && isBuffer(expected)) { - return compare(actual, expected) === 0; +var MeydaAnalyzer = +/*#__PURE__*/ +function () { + function MeydaAnalyzer(options, _this) { + var _this2 = this; - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (util.isDate(actual) && util.isDate(expected)) { - return actual.getTime() === expected.getTime(); + _classCallCheck(this, MeydaAnalyzer); - // 7.3 If the expected value is a RegExp object, the actual value is - // equivalent if it is also a RegExp object with the same source and - // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). - } else if (util.isRegExp(actual) && util.isRegExp(expected)) { - return actual.source === expected.source && - actual.global === expected.global && - actual.multiline === expected.multiline && - actual.lastIndex === expected.lastIndex && - actual.ignoreCase === expected.ignoreCase; + this._m = _this; - // 7.4. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if ((actual === null || typeof actual !== 'object') && - (expected === null || typeof expected !== 'object')) { - return strict ? actual === expected : actual == expected; + if (!options.audioContext) { + throw this._m.errors.noAC; + } else if (options.bufferSize && !_utilities__WEBPACK_IMPORTED_MODULE_0__["isPowerOfTwo"](options.bufferSize)) { + throw this._m._errors.notPow2; + } else if (!options.source) { + throw this._m._errors.noSource; + } - // If both values are instances of typed arrays, wrap their underlying - // ArrayBuffers in a Buffer each to increase performance - // This optimization requires the arrays to have the same type as checked by - // Object.prototype.toString (aka pToString). Never perform binary - // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their - // bit patterns are not identical. - } else if (isView(actual) && isView(expected) && - pToString(actual) === pToString(expected) && - !(actual instanceof Float32Array || - actual instanceof Float64Array)) { - return compare(new Uint8Array(actual.buffer), - new Uint8Array(expected.buffer)) === 0; + this._m.audioContext = options.audioContext; // TODO: validate options - // 7.5 For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else if (isBuffer(actual) !== isBuffer(expected)) { - return false; - } else { - memos = memos || {actual: [], expected: []}; + this._m.bufferSize = options.bufferSize || this._m.bufferSize || 256; + this._m.hopSize = options.hopSize || this._m.hopSize || this._m.bufferSize; + this._m.sampleRate = options.sampleRate || this._m.audioContext.sampleRate || 44100; + this._m.callback = options.callback; + this._m.windowingFunction = options.windowingFunction || 'hanning'; + this._m.featureExtractors = _featureExtractors__WEBPACK_IMPORTED_MODULE_1__; + this._m.EXTRACTION_STARTED = options.startImmediately || false; + this._m.channel = typeof options.channel === 'number' ? options.channel : 0; + this._m.inputs = options.inputs || 1; + this._m.outputs = options.outputs || 1; + this._m.numberOfMFCCCoefficients = options.numberOfMFCCCoefficients || this._m.numberOfMFCCCoefficients || 13; //create nodes - var actualIndex = memos.actual.indexOf(actual); - if (actualIndex !== -1) { - if (actualIndex === memos.expected.indexOf(expected)) { - return true; - } - } + this._m.spn = this._m.audioContext.createScriptProcessor(this._m.bufferSize, this._m.inputs, this._m.outputs); - memos.actual.push(actual); - memos.expected.push(expected); + this._m.spn.connect(this._m.audioContext.destination); - return objEquiv(actual, expected, strict, memos); - } -} + this._m._featuresToExtract = options.featureExtractors || []; //always recalculate BS and MFB when a new Meyda analyzer is created. -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} + this._m.barkScale = _utilities__WEBPACK_IMPORTED_MODULE_0__["createBarkScale"](this._m.bufferSize, this._m.sampleRate, this._m.bufferSize); + this._m.melFilterBank = _utilities__WEBPACK_IMPORTED_MODULE_0__["createMelFilterBank"](Math.max(this._m.melBands, this._m.numberOfMFCCCoefficients), this._m.sampleRate, this._m.bufferSize); + this._m.inputData = null; + this._m.previousInputData = null; + this._m.frame = null; + this._m.previousFrame = null; + this.setSource(options.source); -function objEquiv(a, b, strict, actualVisitedObjects) { - if (a === null || a === undefined || b === null || b === undefined) - return false; - // if one is a primitive, the other must be same - if (util.isPrimitive(a) || util.isPrimitive(b)) - return a === b; - if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) - return false; - var aIsArgs = isArguments(a); - var bIsArgs = isArguments(b); - if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) - return false; - if (aIsArgs) { - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b, strict); - } - var ka = objectKeys(a); - var kb = objectKeys(b); - var key, i; - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length !== kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] !== kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) - return false; - } - return true; -} + this._m.spn.onaudioprocess = function (e) { + if (_this2._m.inputData !== null) { + _this2._m.previousInputData = _this2._m.inputData; + } -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); + _this2._m.inputData = e.inputBuffer.getChannelData(_this2._m.channel); -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } -}; + if (!_this2._m.previousInputData) { + var buffer = _this2._m.inputData; + } else { + var buffer = new Float32Array(_this2._m.previousInputData.length + _this2._m.inputData.length - _this2._m.hopSize); + buffer.set(_this2._m.previousInputData.slice(_this2._m.hopSize)); + buffer.set(_this2._m.inputData, _this2._m.previousInputData.length - _this2._m.hopSize); + } -assert.notDeepStrictEqual = notDeepStrictEqual; -function notDeepStrictEqual(actual, expected, message) { - if (_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); - } -} + ; + var frames = _utilities__WEBPACK_IMPORTED_MODULE_0__["frame"](buffer, _this2._m.bufferSize, _this2._m.hopSize); + frames.forEach(function (f) { + _this2._m.frame = f; + var features = _this2._m.extract(_this2._m._featuresToExtract, _this2._m.frame, _this2._m.previousFrame); // call callback if applicable -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); + if (typeof _this2._m.callback === 'function' && _this2._m.EXTRACTION_STARTED) { + _this2._m.callback(features); + } + + _this2._m.previousFrame = _this2._m.frame; + }); + }; } -}; + /** + * Start feature extraction + * The audio features will be passed to the callback function that was defined + * in the MeydaOptions that were passed to the factory when constructing the + * MeydaAnalyzer. + * @param {(string|Array.)} [features] + * Change the features that Meyda is extracting. Defaults to the features that + * were set upon construction in the options parameter. + * @example + * analyzer.start('chroma'); + */ -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); - } -}; + _createClass(MeydaAnalyzer, [{ + key: "start", + value: function start(features) { + this._m._featuresToExtract = features || this._m._featuresToExtract; + this._m.EXTRACTION_STARTED = true; + } + /** + * Stop feature extraction. + * @example + * analyzer.stop(); + */ -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } + }, { + key: "stop", + value: function stop() { + this._m.EXTRACTION_STARTED = false; + } + /** + * Set the Audio Node for Meyda to listen to. + * @param {AudioNode} source - The Audio Node for Meyda to listen to + * @example + * analyzer.setSource(audioSourceNode); + */ - if (Object.prototype.toString.call(expected) == '[object RegExp]') { - return expected.test(actual); - } + }, { + key: "setSource", + value: function setSource(source) { + this._m.source && this._m.source.disconnect(this._m.spn); + this._m.source = source; - try { - if (actual instanceof expected) { - return true; + this._m.source.connect(this._m.spn); } - } catch (e) { - // Ignore. The instanceof check doesn't work for arrow functions. - } + /** + * Set the channel of the audio node for Meyda to listen to + * @param {number} channel - the index of the channel on the input audio node + * for Meyda to listen to. + * @example + * analyzer.setChannel(0); + */ - if (Error.isPrototypeOf(expected)) { - return false; - } + }, { + key: "setChannel", + value: function setChannel(channel) { + if (channel <= this._m.inputs) { + this._m.channel = channel; + } else { + console.error("Channel ".concat(channel, " does not exist. Make sure you've provided a value for 'inputs' that is greater than ").concat(channel, " when instantiating the MeydaAnalyzer")); + } + } + /** + * Get a set of features from the current frame. + * @param {(string|Array.)} [features] + * Change the features that Meyda is extracting + * @example + * analyzer.get('spectralFlatness'); + */ - return expected.call({}, actual) === true; -} + }, { + key: "get", + value: function get(features) { + if (this._m.inputData) { + return this._m.extract(features || this._m._featuresToExtract, this._m.inputData, this._m.previousInputData); + } else { + return null; + } + } + }]); -function _tryBlock(block) { - var error; - try { - block(); - } catch (e) { - error = e; - } - return error; -} + return MeydaAnalyzer; +}(); -function _throws(shouldThrow, block, expected, message) { - var actual; +/***/ }), - if (typeof block !== 'function') { - throw new TypeError('"block" argument must be a function'); - } +/***/ "./src/utilities.js": +/*!**************************!*\ + !*** ./src/utilities.js ***! + \**************************/ +/*! exports provided: isPowerOfTwo, error, pointwiseBufferMult, applyWindow, createBarkScale, typedToArray, arrayToTyped, _normalize, normalize, normalizeToOne, mean, melToFreq, freqToMel, createMelFilterBank, hzToOctaves, normalizeByColumn, createChromaFilterBank, frame */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (typeof expected === 'string') { - message = expected; - expected = null; - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isPowerOfTwo", function() { return isPowerOfTwo; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "error", function() { return error; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pointwiseBufferMult", function() { return pointwiseBufferMult; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applyWindow", function() { return applyWindow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createBarkScale", function() { return createBarkScale; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "typedToArray", function() { return typedToArray; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "arrayToTyped", function() { return arrayToTyped; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_normalize", function() { return _normalize; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalizeToOne", function() { return normalizeToOne; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mean", function() { return mean; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "melToFreq", function() { return melToFreq; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "freqToMel", function() { return freqToMel; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createMelFilterBank", function() { return createMelFilterBank; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hzToOctaves", function() { return hzToOctaves; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalizeByColumn", function() { return normalizeByColumn; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createChromaFilterBank", function() { return createChromaFilterBank; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "frame", function() { return frame; }); +/* harmony import */ var _windowing__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./windowing */ "./src/windowing.js"); +function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } - actual = _tryBlock(block); +function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); +function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } - if (shouldThrow && !actual) { - fail(actual, expected, 'Missing expected exception' + message); - } +function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } - var userProvidedMessage = typeof message === 'string'; - var isUnwantedException = !shouldThrow && util.isError(actual); - var isUnexpectedException = !shouldThrow && actual && !expected; - if ((isUnwantedException && - userProvidedMessage && - expectedException(actual, expected)) || - isUnexpectedException) { - fail(actual, expected, 'Got unwanted exception' + message); +var windows = {}; +function isPowerOfTwo(num) { + while (num % 2 === 0 && num > 1) { + num /= 2; } - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; - } + return num === 1; +} +function error(message) { + throw new Error('Meyda: ' + message); } +function pointwiseBufferMult(a, b) { + var c = []; -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); + for (var i = 0; i < Math.min(a.length, b.length); i++) { + c[i] = a[i] * b[i]; + } -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws(true, block, error, message); -}; + return c; +} +function applyWindow(signal, windowname) { + if (windowname !== 'rect') { + if (windowname === '' || !windowname) windowname = 'hanning'; + if (!windows[windowname]) windows[windowname] = {}; -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { - _throws(false, block, error, message); -}; + if (!windows[windowname][signal.length]) { + try { + windows[windowname][signal.length] = _windowing__WEBPACK_IMPORTED_MODULE_0__[windowname](signal.length); + } catch (e) { + throw new Error('Invalid windowing function'); + } + } -assert.ifError = function(err) { if (err) throw err; }; + signal = pointwiseBufferMult(signal, windows[windowname][signal.length]); + } -// Expose a strict only variant of assert -function strict(value, message) { - if (!value) fail(value, true, message, '==', strict); + return signal; } -assert.strict = objectAssign(strict, assert, { - equal: assert.strictEqual, - deepEqual: assert.deepStrictEqual, - notEqual: assert.notStrictEqual, - notDeepEqual: assert.notDeepStrictEqual -}); -assert.strict.strict = assert.strict; +function createBarkScale(length, sampleRate, bufferSize) { + var barkScale = new Float32Array(length); -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - if (hasOwn.call(obj, key)) keys.push(key); + for (var i = 0; i < barkScale.length; i++) { + barkScale[i] = i * sampleRate / bufferSize; + barkScale[i] = 13 * Math.atan(barkScale[i] / 1315.8) + 3.5 * Math.atan(Math.pow(barkScale[i] / 7518, 2)); } - return keys; -}; -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"object-assign":134,"util/":128}],126:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } + return barkScale; +} +function typedToArray(t) { + // utility to convert typed arrays to normal arrays + return Array.prototype.slice.call(t); +} +function arrayToTyped(t) { + // utility to convert arrays to typed F32 arrays + return Float32Array.from(t); +} +function _normalize(num, range) { + return num / range; +} +function normalize(a, range) { + return a.map(function (n) { + return _normalize(n, range); + }); +} +function normalizeToOne(a) { + var max = Math.max.apply(null, a); + return a.map(function (n) { + return n / max; + }); +} +function mean(a) { + return a.reduce(function (prev, cur) { + return prev + cur; + }) / a.length; } -},{}],127:[function(require,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; +function _melToFreq(melValue) { + var freqValue = 700 * (Math.exp(melValue / 1125) - 1); + return freqValue; } -},{}],128:[function(require,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } +function _freqToMel(freqValue) { + var melValue = 1125 * Math.log(1 + freqValue / 700); + return melValue; +} - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; +function melToFreq(mV) { + return _melToFreq(mV); +} +function freqToMel(fV) { + return _freqToMel(fV); +} +function createMelFilterBank(numFilters, sampleRate, bufferSize) { + //the +2 is the upper and lower limits + var melValues = new Float32Array(numFilters + 2); + var melValuesInFreq = new Float32Array(numFilters + 2); //Generate limits in Hz - from 0 to the nyquist. + var lowerLimitFreq = 0; + var upperLimitFreq = sampleRate / 2; //Convert the limits to Mel -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } + var lowerLimitMel = _freqToMel(lowerLimitFreq); - if (process.noDeprecation === true) { - return fn; - } + var upperLimitMel = _freqToMel(upperLimitFreq); //Find the range - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - return deprecated; -}; + var range = upperLimitMel - lowerLimitMel; //Find the range as part of the linear interpolation + var valueToAdd = range / (numFilters + 1); + var fftBinsOfFreq = Array(numFilters + 2); -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -}; + for (var i = 0; i < melValues.length; i++) { + // Initialising the mel frequencies + // They're a linear interpolation between the lower and upper limits. + melValues[i] = i * valueToAdd; // Convert back to Hz + melValuesInFreq[i] = _melToFreq(melValues[i]); // Find the corresponding bins -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); + fftBinsOfFreq[i] = Math.floor((bufferSize + 1) * melValuesInFreq[i] / sampleRate); } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; + var filterBank = Array(numFilters); -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; + for (var j = 0; j < filterBank.length; j++) { + // Create a two dimensional array of size numFilters * (buffersize/2)+1 + // pre-populating the arrays with 0s. + filterBank[j] = Array.apply(null, new Array(bufferSize / 2 + 1)).map(Number.prototype.valueOf, 0); //creating the lower and upper slopes for each bin -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; + for (var _i = fftBinsOfFreq[j]; _i < fftBinsOfFreq[j + 1]; _i++) { + filterBank[j][_i] = (_i - fftBinsOfFreq[j]) / (fftBinsOfFreq[j + 1] - fftBinsOfFreq[j]); + } + for (var _i2 = fftBinsOfFreq[j + 1]; _i2 < fftBinsOfFreq[j + 2]; _i2++) { + filterBank[j][_i2] = (fftBinsOfFreq[j + 2] - _i2) / (fftBinsOfFreq[j + 2] - fftBinsOfFreq[j + 1]); + } + } + + return filterBank; +} +function hzToOctaves(freq, A440) { + return Math.log2(16 * freq / A440); +} +function normalizeByColumn(a) { + var emptyRow = a[0].map(function () { + return 0; + }); + var colDenominators = a.reduce(function (acc, row) { + row.forEach(function (cell, j) { + acc[j] += Math.pow(cell, 2); + }); + return acc; + }, emptyRow).map(Math.sqrt); + return a.map(function (row, i) { + return row.map(function (v, j) { + return v / (colDenominators[j] || 1); + }); + }); +} +; +function createChromaFilterBank(numFilters, sampleRate, bufferSize) { + var centerOctave = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5; + var octaveWidth = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 2; + var baseC = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; + var A440 = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 440; + var numOutputBins = Math.floor(bufferSize / 2) + 1; + var frequencyBins = new Array(bufferSize).fill(0).map(function (_, i) { + return numFilters * hzToOctaves(sampleRate * i / bufferSize, A440); + }); // Set a value for the 0 Hz bin that is 1.5 octaves below bin 1 + // (so chroma is 50% rotated from bin 1, and bin width is broad) -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; + frequencyBins[0] = frequencyBins[1] - 1.5 * numFilters; + var binWidthBins = frequencyBins.slice(1).map(function (v, i) { + return Math.max(v - frequencyBins[i]); + }, 1).concat([1]); + var halfNumFilters = Math.round(numFilters / 2); + var filterPeaks = new Array(numFilters).fill(0).map(function (_, i) { + return frequencyBins.map(function (frq) { + return (10 * numFilters + halfNumFilters + frq - i) % numFilters - halfNumFilters; + }); + }); + var weights = filterPeaks.map(function (row, i) { + return row.map(function (_, j) { + return Math.exp(-0.5 * Math.pow(2 * filterPeaks[i][j] / binWidthBins[j], 2)); + }); + }); + weights = normalizeByColumn(weights); - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; + if (octaveWidth) { + var octaveWeights = frequencyBins.map(function (v) { + return Math.exp(-0.5 * Math.pow((v / numFilters - centerOctave) / octaveWidth, 2)); + }); + weights = weights.map(function (row) { + return row.map(function (cell, j) { + return cell * octaveWeights[j]; + }); + }); } -} + if (baseC) { + weights = [].concat(_toConsumableArray(weights.slice(3)), _toConsumableArray(weights.slice(0, 3))); + } -function stylizeNoColor(str, styleType) { - return str; + return weights.map(function (row) { + return row.slice(0, numOutputBins); + }); } +function frame(buffer, frameLength, hopLength) { + if (buffer.length < frameLength) { + throw new Error('Buffer is too short for frame length'); + } + if (hopLength < 1) { + throw new Error('Hop length cannot be less that 1'); + } -function arrayToHash(array) { - var hash = {}; + if (frameLength < 1) { + throw new Error('Frame length cannot be less that 1'); + } - array.forEach(function(val, idx) { - hash[val] = true; + var numFrames = 1 + Math.floor((buffer.length - frameLength) / hopLength); + return new Array(numFrames).fill(0).map(function (_, i) { + return buffer.slice(i * hopLength, i * hopLength + frameLength); }); - - return hash; } +/***/ }), -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } +/***/ "./src/windowing.js": +/*!**************************!*\ + !*** ./src/windowing.js ***! + \**************************/ +/*! exports provided: blackman, sine, hanning, hamming */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "blackman", function() { return blackman; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sine", function() { return sine; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hanning", function() { return hanning; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hamming", function() { return hamming; }); +function blackman(size) { + var blackmanBuffer = new Float32Array(size); + var coeff1 = 2 * Math.PI / (size - 1); + var coeff2 = 2 * coeff1; //According to http://uk.mathworks.com/help/signal/ref/blackman.html + //first half of the window - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } + for (var i = 0; i < size / 2; i++) { + blackmanBuffer[i] = 0.42 - 0.5 * Math.cos(i * coeff1) + 0.08 * Math.cos(i * coeff2); + } //second half of the window - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } + for (var _i = size / 2; _i > 0; _i--) { + blackmanBuffer[size - _i] = blackmanBuffer[_i - 1]; } - var base = '', array = false, braces = ['{', '}']; + return blackmanBuffer; +} +function sine(size) { + var coeff = Math.PI / (size - 1); + var sineBuffer = new Float32Array(size); - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; + for (var i = 0; i < size; i++) { + sineBuffer[i] = Math.sin(coeff * i); } - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } + return sineBuffer; +} +function hanning(size) { + var hanningBuffer = new Float32Array(size); - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); + for (var i = 0; i < size; i++) { + // According to the R documentation + // http://ugrad.stat.ubc.ca/R/library/e1071/html/hanning.window.html + hanningBuffer[i] = 0.5 - 0.5 * Math.cos(2 * Math.PI * i / (size - 1)); } - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } + return hanningBuffer; +} +function hamming(size) { + var hammingBuffer = new Float32Array(size); - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); + for (var i = 0; i < size; i++) { + //According to http://uk.mathworks.com/help/signal/ref/hamming.html + hammingBuffer[i] = 0.54 - 0.46 * Math.cos(2 * Math.PI * (i / size - 1)); } - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } + return hammingBuffer; +} - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } +/***/ }) - ctx.seen.push(value); +/******/ }); +}); - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } +},{}],93:[function(require,module,exports){ +assert.notEqual = notEqual +assert.notOk = notOk +assert.equal = equal +assert.ok = assert - ctx.seen.pop(); +module.exports = assert - return reduceToSingleString(output, base, braces); +function equal (a, b, m) { + assert(a == b, m) // eslint-disable-line eqeqeq } - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); +function notEqual (a, b, m) { + assert(a != b, m) // eslint-disable-line eqeqeq } - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; +function notOk (t, m) { + assert(!t, m) } - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; +function assert (t, m) { + if (!t) throw new Error(m || 'AssertionError') } +},{}],94:[function(require,module,exports){ +var splice = require('remove-array-items') +var nanotiming = require('nanotiming') +var assert = require('assert') -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } +module.exports = Nanobus - return name + ': ' + str; -} +function Nanobus (name) { + if (!(this instanceof Nanobus)) return new Nanobus(name) + this._name = name || 'nanobus' + this._starListeners = [] + this._listeners = {} +} -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); +Nanobus.prototype.emit = function (eventName) { + assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.emit: eventName should be type string or symbol') - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; + var data = [] + for (var i = 1, len = arguments.length; i < len; i++) { + data.push(arguments[i]) } - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} + var emitTiming = nanotiming(this._name + "('" + eventName.toString() + "')") + var listeners = this._listeners[eventName] + if (listeners && listeners.length > 0) { + this._emit(this._listeners[eventName], data) + } + if (this._starListeners.length > 0) { + this._emit(this._starListeners, eventName, data, emitTiming.uuid) + } + emitTiming() -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); + return this } -exports.isArray = isArray; -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; +Nanobus.prototype.on = Nanobus.prototype.addListener = function (eventName, listener) { + assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.on: eventName should be type string or symbol') + assert.equal(typeof listener, 'function', 'nanobus.on: listener should be type function') -function isNull(arg) { - return arg === null; + if (eventName === '*') { + this._starListeners.push(listener) + } else { + if (!this._listeners[eventName]) this._listeners[eventName] = [] + this._listeners[eventName].push(listener) + } + return this } -exports.isNull = isNull; -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; +Nanobus.prototype.prependListener = function (eventName, listener) { + assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.prependListener: eventName should be type string or symbol') + assert.equal(typeof listener, 'function', 'nanobus.prependListener: listener should be type function') -function isNumber(arg) { - return typeof arg === 'number'; + if (eventName === '*') { + this._starListeners.unshift(listener) + } else { + if (!this._listeners[eventName]) this._listeners[eventName] = [] + this._listeners[eventName].unshift(listener) + } + return this } -exports.isNumber = isNumber; -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; +Nanobus.prototype.once = function (eventName, listener) { + assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.once: eventName should be type string or symbol') + assert.equal(typeof listener, 'function', 'nanobus.once: listener should be type function') -function isSymbol(arg) { - return typeof arg === 'symbol'; + var self = this + this.on(eventName, once) + function once () { + listener.apply(self, arguments) + self.removeListener(eventName, once) + } + return this } -exports.isSymbol = isSymbol; -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; +Nanobus.prototype.prependOnceListener = function (eventName, listener) { + assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.prependOnceListener: eventName should be type string or symbol') + assert.equal(typeof listener, 'function', 'nanobus.prependOnceListener: listener should be type function') -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; + var self = this + this.prependListener(eventName, once) + function once () { + listener.apply(self, arguments) + self.removeListener(eventName, once) + } + return this } -exports.isRegExp = isRegExp; -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; +Nanobus.prototype.removeListener = function (eventName, listener) { + assert.ok(typeof eventName === 'string' || typeof eventName === 'symbol', 'nanobus.removeListener: eventName should be type string or symbol') + assert.equal(typeof listener, 'function', 'nanobus.removeListener: listener should be type function') -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; + if (eventName === '*') { + this._starListeners = this._starListeners.slice() + return remove(this._starListeners, listener) + } else { + if (typeof this._listeners[eventName] !== 'undefined') { + this._listeners[eventName] = this._listeners[eventName].slice() + } -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; + return remove(this._listeners[eventName], listener) + } -function isFunction(arg) { - return typeof arg === 'function'; + function remove (arr, listener) { + if (!arr) return + var index = arr.indexOf(listener) + if (index !== -1) { + splice(arr, index, 1) + return true + } + } } -exports.isFunction = isFunction; -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; +Nanobus.prototype.removeAllListeners = function (eventName) { + if (eventName) { + if (eventName === '*') { + this._starListeners = [] + } else { + this._listeners[eventName] = [] + } + } else { + this._starListeners = [] + this._listeners = {} + } + return this } -exports.isPrimitive = isPrimitive; -exports.isBuffer = require('./support/isBuffer'); +Nanobus.prototype.listeners = function (eventName) { + var listeners = eventName !== '*' + ? this._listeners[eventName] + : this._starListeners -function objectToString(o) { - return Object.prototype.toString.call(o); + var ret = [] + if (listeners) { + var ilength = listeners.length + for (var i = 0; i < ilength; i++) ret.push(listeners[i]) + } + return ret } +Nanobus.prototype._emit = function (arr, eventName, data, uuid) { + if (typeof arr === 'undefined') return + if (arr.length === 0) return + if (data === undefined) { + data = eventName + eventName = null + } + + if (eventName) { + if (uuid !== undefined) { + data = [eventName].concat(data, uuid) + } else { + data = [eventName].concat(data) + } + } -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); + var length = arr.length + for (var i = 0; i < length; i++) { + var listener = arr[i] + listener.apply(listener, data) + } } +},{"assert":93,"nanotiming":113,"remove-array-items":125}],95:[function(require,module,exports){ +var document = require('global/document') +var nanotiming = require('nanotiming') +var morph = require('nanomorph') +var onload = require('on-load') +var OL_KEY_ID = onload.KEY_ID +var OL_ATTR_ID = onload.KEY_ATTR +var assert = require('assert') -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; +module.exports = Nanocomponent -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); +function makeID () { + return 'ncid-' + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1) } +function Nanocomponent (name) { + this._hasWindow = typeof window !== 'undefined' + this._id = null // represents the id of the root node + this._ncID = null // internal nanocomponent id + this._olID = null + this._proxy = null + this._loaded = false // Used to debounce on-load when child-reordering + this._rootNodeName = null + this._name = name || 'nanocomponent' + this._rerender = false -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; + this._handleLoad = this._handleLoad.bind(this) + this._handleUnload = this._handleUnload.bind(this) + this._arguments = [] -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = require('inherits'); + var self = this -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; + Object.defineProperty(this, 'element', { + get: function () { + var el = document.getElementById(self._id) + if (el) return el.dataset.nanocomponent === self._ncID ? el : undefined + } + }) +} - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; +Nanocomponent.prototype.render = function () { + var renderTiming = nanotiming(this._name + '.render') + var self = this + var args = new Array(arguments.length) + var el + for (var i = 0; i < arguments.length; i++) args[i] = arguments[i] + if (!this._hasWindow) { + var createTiming = nanotiming(this._name + '.create') + el = this.createElement.apply(this, args) + createTiming() + renderTiming() + return el + } else if (this.element) { + el = this.element // retain reference, as the ID might change on render + var updateTiming = nanotiming(this._name + '.update') + var shouldUpdate = this._rerender || this.update.apply(this, args) + updateTiming() + if (this._rerender) this._rerender = false + if (shouldUpdate) { + var desiredHtml = this._handleRender(args) + var morphTiming = nanotiming(this._name + '.morph') + morph(el, desiredHtml) + morphTiming() + if (this.afterupdate) this.afterupdate(el) + } + if (!this._proxy) { this._proxy = this._createProxy() } + renderTiming() + return this._proxy + } else { + this._reset() + el = this._handleRender(args) + if (this.beforerender) this.beforerender(el) + if (this.load || this.unload || this.afterreorder) { + onload(el, self._handleLoad, self._handleUnload, self._ncID) + this._olID = el.dataset[OL_KEY_ID] + } + renderTiming() + return el } - return origin; -}; - -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); } -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":127,"_process":135,"inherits":126}],129:[function(require,module,exports){ -'use strict' - -exports.byteLength = byteLength -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray - -var lookup = [] -var revLookup = [] -var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array - -var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i +Nanocomponent.prototype.rerender = function () { + assert(this.element, 'nanocomponent: cant rerender on an unmounted dom node') + this._rerender = true + this.render.apply(this, this._arguments) } -// Support decoding URL-safe base64 strings, as Node.js does. -// See: https://en.wikipedia.org/wiki/Base64#URL_applications -revLookup['-'.charCodeAt(0)] = 62 -revLookup['_'.charCodeAt(0)] = 63 - -function getLens (b64) { - var len = b64.length +Nanocomponent.prototype._handleRender = function (args) { + var createElementTiming = nanotiming(this._name + '.createElement') + var el = this.createElement.apply(this, args) + createElementTiming() + if (!this._rootNodeName) this._rootNodeName = el.nodeName + assert(el instanceof window.Element, 'nanocomponent: createElement should return a single DOM node') + assert.equal(this._rootNodeName, el.nodeName, 'nanocomponent: root node types cannot differ between re-renders') + this._arguments = args + return this._brandNode(this._ensureID(el)) +} - if (len % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') +Nanocomponent.prototype._createProxy = function () { + var proxy = document.createElement(this._rootNodeName) + var self = this + this._brandNode(proxy) + proxy.id = this._id + proxy.setAttribute('data-proxy', '') + proxy.isSameNode = function (el) { + return (el && el.dataset.nanocomponent === self._ncID) } + return proxy +} - // Trim off extra bytes after placeholder bytes are found - // See: https://github.com/beatgammit/base64-js/issues/42 - var validLen = b64.indexOf('=') - if (validLen === -1) validLen = len - - var placeHoldersLen = validLen === len - ? 0 - : 4 - (validLen % 4) +Nanocomponent.prototype._reset = function () { + this._ncID = makeID() + this._olID = null + this._id = null + this._proxy = null + this._rootNodeName = null +} - return [validLen, placeHoldersLen] +Nanocomponent.prototype._brandNode = function (node) { + node.setAttribute('data-nanocomponent', this._ncID) + if (this._olID) node.setAttribute(OL_ATTR_ID, this._olID) + return node } -// base64 is 4/3 + up to two characters of the original data -function byteLength (b64) { - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] - return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +Nanocomponent.prototype._ensureID = function (node) { + if (node.id) this._id = node.id + else node.id = this._id = this._ncID + // Update proxy node ID if it changed + if (this._proxy && this._proxy.id !== this._id) this._proxy.id = this._id + return node } -function _byteLength (b64, validLen, placeHoldersLen) { - return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +Nanocomponent.prototype._handleLoad = function (el) { + if (this._loaded) { + if (this.afterreorder) this.afterreorder(el) + return // Debounce child-reorders + } + this._loaded = true + if (this.load) this.load(el) } -function toByteArray (b64) { - var tmp - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] +Nanocomponent.prototype._handleUnload = function (el) { + if (this.element) return // Debounce child-reorders + this._loaded = false + if (this.unload) this.unload(el) +} - var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) +Nanocomponent.prototype.createElement = function () { + throw new Error('nanocomponent: createElement should be implemented!') +} - var curByte = 0 +Nanocomponent.prototype.update = function () { + throw new Error('nanocomponent: update should be implemented!') +} - // if there are placeholders, only get up to the last complete 4 chars - var len = placeHoldersLen > 0 - ? validLen - 4 - : validLen +},{"assert":93,"global/document":64,"nanomorph":106,"nanotiming":113,"on-load":116}],96:[function(require,module,exports){ +var assert = require('assert') - var i - for (i = 0; i < len; i += 4) { - tmp = - (revLookup[b64.charCodeAt(i)] << 18) | - (revLookup[b64.charCodeAt(i + 1)] << 12) | - (revLookup[b64.charCodeAt(i + 2)] << 6) | - revLookup[b64.charCodeAt(i + 3)] - arr[curByte++] = (tmp >> 16) & 0xFF - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF - } +var safeExternalLink = /(noopener|noreferrer) (noopener|noreferrer)/ +var protocolLink = /^[\w-_]+:/ - if (placeHoldersLen === 2) { - tmp = - (revLookup[b64.charCodeAt(i)] << 2) | - (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[curByte++] = tmp & 0xFF - } +module.exports = href - if (placeHoldersLen === 1) { - tmp = - (revLookup[b64.charCodeAt(i)] << 10) | - (revLookup[b64.charCodeAt(i + 1)] << 4) | - (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF - } +function href (cb, root) { + assert.notEqual(typeof window, 'undefined', 'nanohref: expected window to exist') - return arr -} + root = root || window.document -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + - lookup[num >> 12 & 0x3F] + - lookup[num >> 6 & 0x3F] + - lookup[num & 0x3F] -} + assert.equal(typeof cb, 'function', 'nanohref: cb should be type function') + assert.equal(typeof root, 'object', 'nanohref: root should be type object') -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = - ((uint8[i] << 16) & 0xFF0000) + - ((uint8[i + 1] << 8) & 0xFF00) + - (uint8[i + 2] & 0xFF) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} + window.addEventListener('click', function (e) { + if ((e.button && e.button !== 0) || + e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || + e.defaultPrevented) return -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 + var anchor = (function traverse (node) { + if (!node || node === root) return + if (node.localName !== 'a' || node.href === undefined) { + return traverse(node.parentNode) + } + return node + })(e.target) - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk( - uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) - )) - } + if (!anchor) return - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - parts.push( - lookup[tmp >> 2] + - lookup[(tmp << 4) & 0x3F] + - '==' - ) - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + uint8[len - 1] - parts.push( - lookup[tmp >> 10] + - lookup[(tmp >> 4) & 0x3F] + - lookup[(tmp << 2) & 0x3F] + - '=' - ) - } + if (window.location.protocol !== anchor.protocol || + window.location.hostname !== anchor.hostname || + window.location.port !== anchor.port || + anchor.hasAttribute('data-nanohref-ignore') || + anchor.hasAttribute('download') || + (anchor.getAttribute('target') === '_blank' && + safeExternalLink.test(anchor.getAttribute('rel'))) || + protocolLink.test(anchor.getAttribute('href'))) return - return parts.join('') + e.preventDefault() + cb(anchor) + }) } -},{}],130:[function(require,module,exports){ - -},{}],131:[function(require,module,exports){ -(function (Buffer){ -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -/* eslint-disable no-proto */ - +},{"assert":93}],97:[function(require,module,exports){ 'use strict' -var base64 = require('base64-js') -var ieee754 = require('ieee754') +var trailingNewlineRegex = /\n[\s]+$/ +var leadingNewlineRegex = /^\n[\s]+/ +var trailingSpaceRegex = /[\s]+$/ +var leadingSpaceRegex = /^[\s]+/ +var multiSpaceRegex = /[\n\s]+/g -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 +var TEXT_TAGS = [ + 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'data', 'dfn', 'em', 'i', + 'kbd', 'mark', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'amp', 'small', 'span', + 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr' +] -var K_MAX_LENGTH = 0x7fffffff -exports.kMaxLength = K_MAX_LENGTH +var VERBATIM_TAGS = [ + 'code', 'pre', 'textarea' +] -/** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Print warning and recommend using `buffer` v4.x which has an Object - * implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * We report that the browser does not support typed arrays if the are not subclassable - * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` - * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support - * for __proto__ and has a buggy typed array implementation. - */ -Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() +module.exports = function appendChild (el, childs) { + if (!Array.isArray(childs)) return -if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && - typeof console.error === 'function') { - console.error( - 'This browser lacks typed array (Uint8Array) support which is required by ' + - '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' - ) -} + var nodeName = el.nodeName.toLowerCase() -function typedArraySupport () { - // Can typed array instances can be augmented? - try { - var arr = new Uint8Array(1) - arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } - return arr.foo() === 42 - } catch (e) { - return false - } -} + var hadText = false + var value, leader -Object.defineProperty(Buffer.prototype, 'parent', { - enumerable: true, - get: function () { - if (!Buffer.isBuffer(this)) return undefined - return this.buffer - } -}) + for (var i = 0, len = childs.length; i < len; i++) { + var node = childs[i] + if (Array.isArray(node)) { + appendChild(el, node) + continue + } -Object.defineProperty(Buffer.prototype, 'offset', { - enumerable: true, - get: function () { - if (!Buffer.isBuffer(this)) return undefined - return this.byteOffset - } -}) + if (typeof node === 'number' || + typeof node === 'boolean' || + typeof node === 'function' || + node instanceof Date || + node instanceof RegExp) { + node = node.toString() + } -function createBuffer (length) { - if (length > K_MAX_LENGTH) { - throw new RangeError('The value "' + length + '" is invalid for option "size"') - } - // Return an augmented `Uint8Array` instance - var buf = new Uint8Array(length) - buf.__proto__ = Buffer.prototype - return buf -} + var lastChild = el.childNodes[el.childNodes.length - 1] -/** - * The Buffer constructor returns instances of `Uint8Array` that have their - * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of - * `Uint8Array`, so the returned instances will have all the node `Buffer` methods - * and the `Uint8Array` methods. Square bracket notation works as expected -- it - * returns a single octet. - * - * The `Uint8Array` prototype remains unmodified. - */ + // Iterate over text nodes + if (typeof node === 'string') { + hadText = true -function Buffer (arg, encodingOrOffset, length) { - // Common case. - if (typeof arg === 'number') { - if (typeof encodingOrOffset === 'string') { - throw new TypeError( - 'The "string" argument must be of type string. Received type number' - ) - } - return allocUnsafe(arg) - } - return from(arg, encodingOrOffset, length) -} + // If we already had text, append to the existing text + if (lastChild && lastChild.nodeName === '#text') { + lastChild.nodeValue += node -// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 -if (typeof Symbol !== 'undefined' && Symbol.species != null && - Buffer[Symbol.species] === Buffer) { - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true, - enumerable: false, - writable: false - }) -} + // We didn't have a text node yet, create one + } else { + node = el.ownerDocument.createTextNode(node) + el.appendChild(node) + lastChild = node + } -Buffer.poolSize = 8192 // not used by this implementation + // If this is the last of the child nodes, make sure we close it out + // right + if (i === len - 1) { + hadText = false + // Trim the child text nodes if the current node isn't a + // node where whitespace matters. + if (TEXT_TAGS.indexOf(nodeName) === -1 && + VERBATIM_TAGS.indexOf(nodeName) === -1) { + value = lastChild.nodeValue + .replace(leadingNewlineRegex, '') + .replace(trailingSpaceRegex, '') + .replace(trailingNewlineRegex, '') + .replace(multiSpaceRegex, ' ') + if (value === '') { + el.removeChild(lastChild) + } else { + lastChild.nodeValue = value + } + } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { + // The very first node in the list should not have leading + // whitespace. Sibling text nodes should have whitespace if there + // was any. + leader = i === 0 ? '' : ' ' + value = lastChild.nodeValue + .replace(leadingNewlineRegex, leader) + .replace(leadingSpaceRegex, ' ') + .replace(trailingSpaceRegex, '') + .replace(trailingNewlineRegex, '') + .replace(multiSpaceRegex, ' ') + lastChild.nodeValue = value + } + } -function from (value, encodingOrOffset, length) { - if (typeof value === 'string') { - return fromString(value, encodingOrOffset) - } + // Iterate over DOM nodes + } else if (node && node.nodeType) { + // If the last node was a text node, make sure it is properly closed out + if (hadText) { + hadText = false - if (ArrayBuffer.isView(value)) { - return fromArrayLike(value) - } + // Trim the child text nodes if the current node isn't a + // text node or a code node + if (TEXT_TAGS.indexOf(nodeName) === -1 && + VERBATIM_TAGS.indexOf(nodeName) === -1) { + value = lastChild.nodeValue + .replace(leadingNewlineRegex, '') + .replace(trailingNewlineRegex, ' ') + .replace(multiSpaceRegex, ' ') - if (value == null) { - throw TypeError( - 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + - 'or Array-like Object. Received type ' + (typeof value) - ) - } + // Remove empty text nodes, append otherwise + if (value === '') { + el.removeChild(lastChild) + } else { + lastChild.nodeValue = value + } + // Trim the child nodes but preserve the appropriate whitespace + } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { + value = lastChild.nodeValue + .replace(leadingSpaceRegex, ' ') + .replace(leadingNewlineRegex, '') + .replace(trailingNewlineRegex, ' ') + .replace(multiSpaceRegex, ' ') + lastChild.nodeValue = value + } + } - if (isInstance(value, ArrayBuffer) || - (value && isInstance(value.buffer, ArrayBuffer))) { - return fromArrayBuffer(value, encodingOrOffset, length) - } + // Store the last nodename + var _nodeName = node.nodeName + if (_nodeName) nodeName = _nodeName.toLowerCase() - if (typeof value === 'number') { - throw new TypeError( - 'The "value" argument must not be of type number. Received type number' - ) + // Append the node to the DOM + el.appendChild(node) + } } +} - var valueOf = value.valueOf && value.valueOf() - if (valueOf != null && valueOf !== value) { - return Buffer.from(valueOf, encodingOrOffset, length) - } +},{}],98:[function(require,module,exports){ +'use strict' - var b = fromObject(value) - if (b) return b +module.exports = [ + 'async', 'autofocus', 'autoplay', 'checked', 'controls', 'default', + 'defaultchecked', 'defer', 'disabled', 'formnovalidate', 'hidden', + 'ismap', 'loop', 'multiple', 'muted', 'novalidate', 'open', 'playsinline', + 'readonly', 'required', 'reversed', 'selected' +] - if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && - typeof value[Symbol.toPrimitive] === 'function') { - return Buffer.from( - value[Symbol.toPrimitive]('string'), encodingOrOffset, length - ) - } +},{}],99:[function(require,module,exports){ +module.exports = require('./dom')(document) - throw new TypeError( - 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + - 'or Array-like Object. Received type ' + (typeof value) - ) -} +},{"./dom":101}],100:[function(require,module,exports){ +'use strict' -/** - * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError - * if value is a number. - * Buffer.from(str[, encoding]) - * Buffer.from(array) - * Buffer.from(buffer) - * Buffer.from(arrayBuffer[, byteOffset[, length]]) - **/ -Buffer.from = function (value, encodingOrOffset, length) { - return from(value, encodingOrOffset, length) -} +module.exports = [ + 'indeterminate' +] -// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: -// https://github.com/feross/buffer/pull/148 -Buffer.prototype.__proto__ = Uint8Array.prototype -Buffer.__proto__ = Uint8Array +},{}],101:[function(require,module,exports){ +'use strict' -function assertSize (size) { - if (typeof size !== 'number') { - throw new TypeError('"size" argument must be of type number') - } else if (size < 0) { - throw new RangeError('The value "' + size + '" is invalid for option "size"') - } -} +var hyperx = require('hyperx') +var appendChild = require('./append-child') +var SVG_TAGS = require('./svg-tags') +var BOOL_PROPS = require('./bool-props') +// Props that need to be set directly rather than with el.setAttribute() +var DIRECT_PROPS = require('./direct-props') -function alloc (size, fill, encoding) { - assertSize(size) - if (size <= 0) { - return createBuffer(size) - } - if (fill !== undefined) { - // Only pay attention to encoding if it's a string. This - // prevents accidentally sending in a number that would - // be interpretted as a start offset. - return typeof encoding === 'string' - ? createBuffer(size).fill(fill, encoding) - : createBuffer(size).fill(fill) - } - return createBuffer(size) -} +var SVGNS = 'http://www.w3.org/2000/svg' +var XLINKNS = 'http://www.w3.org/1999/xlink' -/** - * Creates a new filled Buffer instance. - * alloc(size[, fill[, encoding]]) - **/ -Buffer.alloc = function (size, fill, encoding) { - return alloc(size, fill, encoding) -} +var COMMENT_TAG = '!--' -function allocUnsafe (size) { - assertSize(size) - return createBuffer(size < 0 ? 0 : checked(size) | 0) -} +module.exports = function (document) { + function nanoHtmlCreateElement (tag, props, children) { + var el -/** - * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. - * */ -Buffer.allocUnsafe = function (size) { - return allocUnsafe(size) -} -/** - * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. - */ -Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(size) -} + // If an svg tag, it needs a namespace + if (SVG_TAGS.indexOf(tag) !== -1) { + props.namespace = SVGNS + } -function fromString (string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } + // If we are using a namespace + var ns = false + if (props.namespace) { + ns = props.namespace + delete props.namespace + } - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } + // If we are extending a builtin element + var isCustomElement = false + if (props.is) { + isCustomElement = props.is + delete props.is + } - var length = byteLength(string, encoding) | 0 - var buf = createBuffer(length) + // Create the element + if (ns) { + if (isCustomElement) { + el = document.createElementNS(ns, tag, { is: isCustomElement }) + } else { + el = document.createElementNS(ns, tag) + } + } else if (tag === COMMENT_TAG) { + return document.createComment(props.comment) + } else if (isCustomElement) { + el = document.createElement(tag, { is: isCustomElement }) + } else { + el = document.createElement(tag) + } - var actual = buf.write(string, encoding) + // Create the properties + for (var p in props) { + if (props.hasOwnProperty(p)) { + var key = p.toLowerCase() + var val = props[p] + // Normalize className + if (key === 'classname') { + key = 'class' + p = 'class' + } + // The for attribute gets transformed to htmlFor, but we just set as for + if (p === 'htmlFor') { + p = 'for' + } + // If a property is boolean, set itself to the key + if (BOOL_PROPS.indexOf(key) !== -1) { + if (String(val) === 'true') val = key + else if (String(val) === 'false') continue + } + // If a property prefers being set directly vs setAttribute + if (key.slice(0, 2) === 'on' || DIRECT_PROPS.indexOf(key) !== -1) { + el[p] = val + } else { + if (ns) { + if (p === 'xlink:href') { + el.setAttributeNS(XLINKNS, p, val) + } else if (/^xmlns($|:)/i.test(p)) { + // skip xmlns definitions + } else { + el.setAttributeNS(null, p, val) + } + } else { + el.setAttribute(p, val) + } + } + } + } - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - buf = buf.slice(0, actual) + appendChild(el, children) + return el } - return buf -} - -function fromArrayLike (array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0 - var buf = createBuffer(length) - for (var i = 0; i < length; i += 1) { - buf[i] = array[i] & 255 + function createFragment (nodes) { + var fragment = document.createDocumentFragment() + for (var i = 0; i < nodes.length; i++) { + if (nodes[i] == null) continue + if (Array.isArray(nodes[i])) { + fragment.appendChild(createFragment(nodes[i])) + } else { + if (typeof nodes[i] === 'string') nodes[i] = document.createTextNode(nodes[i]) + fragment.appendChild(nodes[i]) + } + } + return fragment } - return buf -} -function fromArrayBuffer (array, byteOffset, length) { - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('"offset" is outside of buffer bounds') - } + var exports = hyperx(nanoHtmlCreateElement, { + comments: true, + createFragment: createFragment + }) + exports.default = exports + exports.createComment = nanoHtmlCreateElement + return exports +} - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('"length" is outside of buffer bounds') - } +},{"./append-child":97,"./bool-props":98,"./direct-props":100,"./svg-tags":103,"hyperx":87}],102:[function(require,module,exports){ +'use strict' - var buf - if (byteOffset === undefined && length === undefined) { - buf = new Uint8Array(array) - } else if (length === undefined) { - buf = new Uint8Array(array, byteOffset) - } else { - buf = new Uint8Array(array, byteOffset, length) - } +function nanohtmlRawBrowser (tag) { + var el = document.createElement('div') + el.innerHTML = tag + return toArray(el.childNodes) +} - // Return an augmented `Uint8Array` instance - buf.__proto__ = Buffer.prototype - return buf +function toArray (arr) { + return Array.isArray(arr) ? arr : [].slice.call(arr) } -function fromObject (obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0 - var buf = createBuffer(len) +module.exports = nanohtmlRawBrowser - if (buf.length === 0) { - return buf - } +},{}],103:[function(require,module,exports){ +'use strict' - obj.copy(buf, 0, 0, len) - return buf - } +module.exports = [ + 'svg', 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', + 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', + 'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', + 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', + 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', + 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', + 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', + 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', + 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', + 'font-face-uri', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', + 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', + 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', + 'set', 'stop', 'switch', 'symbol', 'text', 'textPath', 'title', 'tref', + 'tspan', 'use', 'view', 'vkern' +] - if (obj.length !== undefined) { - if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { - return createBuffer(0) - } - return fromArrayLike(obj) - } +},{}],104:[function(require,module,exports){ +var assert = require('assert') - if (obj.type === 'Buffer' && Array.isArray(obj.data)) { - return fromArrayLike(obj.data) - } +var emojis = { + trace: '🔍', + debug: '🐛', + info: '✨', + warn: '⚠️', + error: '🚨', + fatal: '💀' } -function checked (length) { - // Note: cannot use `length < K_MAX_LENGTH` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= K_MAX_LENGTH) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') - } - return length | 0 +var levels = { + trace: 10, + debug: 20, + info: 30, + warn: 40, + error: 50, + fatal: 60 } -function SlowBuffer (length) { - if (+length != length) { // eslint-disable-line eqeqeq - length = 0 - } - return Buffer.alloc(+length) +var defaultColors = { + foreground: '#d3c0c8', + background: '#2d2d2d', + black: '#2d2d2d', + red: '#f2777a', + green: '#99cc99', + yellow: '#ffcc66', + blue: '#6699cc', + magenta: '#cc99cc', + cyan: '#66cccc', + white: '#d3d0c8', + brightBlack: '#747369' } -Buffer.isBuffer = function isBuffer (b) { - return b != null && b._isBuffer === true && - b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false -} +module.exports = Nanologger -Buffer.compare = function compare (a, b) { - if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) - if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError( - 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' - ) - } +function Nanologger (name, opts) { + opts = opts || {} + if (!(this instanceof Nanologger)) return new Nanologger(name, opts) - if (a === b) return 0 + assert.equal(typeof opts, 'object', 'nanologger: opts should be type object') - var x = a.length - var y = b.length + this._name = name || '' + this._colors = Object.assign({}, defaultColors, opts.colors || {}) - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i] - y = b[i] - break - } + try { + this.logLevel = window.localStorage.getItem('logLevel') || 'info' + } catch (e) { + this.logLevel = 'info' } - if (x < y) return -1 - if (y < x) return 1 - return 0 + this._logLevel = levels[this.logLevel] } -Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'latin1': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } +Nanologger.prototype.trace = function () { + var args = [ 'trace' ] + for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) + this._print.apply(this, args) } -Buffer.concat = function concat (list, length) { - if (!Array.isArray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - - if (list.length === 0) { - return Buffer.alloc(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; ++i) { - length += list[i].length - } - } - - var buffer = Buffer.allocUnsafe(length) - var pos = 0 - for (i = 0; i < list.length; ++i) { - var buf = list[i] - if (isInstance(buf, Uint8Array)) { - buf = Buffer.from(buf) - } - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos) - pos += buf.length - } - return buffer +Nanologger.prototype.debug = function () { + var args = [ 'debug' ] + for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) + this._print.apply(this, args) } -function byteLength (string, encoding) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - throw new TypeError( - 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + - 'Received type ' + typeof string - ) - } +Nanologger.prototype.info = function () { + var args = [ 'info' ] + for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) + this._print.apply(this, args) +} - var len = string.length - var mustMatch = (arguments.length > 2 && arguments[2] === true) - if (!mustMatch && len === 0) return 0 +Nanologger.prototype.warn = function () { + var args = [ 'warn' ] + for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) + this._print.apply(this, args) +} - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len - case 'utf8': - case 'utf-8': - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) { - return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 - } - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } +Nanologger.prototype.error = function () { + var args = [ 'error' ] + for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) + this._print.apply(this, args) } -Buffer.byteLength = byteLength -function slowToString (encoding, start, end) { - var loweredCase = false +Nanologger.prototype.fatal = function () { + var args = [ 'fatal' ] + for (var i = 0, len = arguments.length; i < len; i++) args.push(arguments[i]) + this._print.apply(this, args) +} - // No need to verify that "this.length <= MAX_UINT32" since it's a read-only - // property of a typed array. +Nanologger.prototype._print = function (level) { + if (levels[level] < this._logLevel) return - // This behaves neither like String nor Uint8Array in that we set start/end - // to their upper/lower bounds if the value passed is out of range. - // undefined is handled specially as per ECMA-262 6th Edition, - // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. - if (start === undefined || start < 0) { - start = 0 - } - // Return early if start > this.length. Done here to prevent potential uint32 - // coercion fail below. - if (start > this.length) { - return '' - } + var time = getTimeStamp() + var emoji = emojis[level] + var name = this._name || 'unknown' - if (end === undefined || end > this.length) { - end = this.length - } + var msgColor = (level === 'error' || level.fatal) + ? this._colors.red + : level === 'warn' + ? this._colors.yellow + : this._colors.green - if (end <= 0) { - return '' - } + var objs = [] + var args = [ null ] + var msg = '%c%s ' + emoji + ' %c%s' - // Force coersion to uint32. This will also coerce falsey/NaN values to 0. - end >>>= 0 - start >>>= 0 + args.push(color(this._colors.brightBlack), time) + args.push(color(this._colors.magenta), name) - if (end <= start) { - return '' + for (var i = 1, len = arguments.length; i < len; i++) { + var arg = arguments[i] + if (typeof arg === 'string') { + if (i === 1) { + // first string argument is in color + msg += ' %c%s' + args.push(color(msgColor)) + args.push(arg) + } else if (/ms$/.test(arg)) { + // arguments finishing with 'ms', grey out + msg += ' %c%s' + args.push(color(this._colors.brightBlack)) + args.push(arg) + } else { + // normal colors + msg += ' %c%s' + args.push(color(this._colors.white)) + args.push(arg) + } + } else if (typeof arg === 'number') { + msg += ' %c%d' + args.push(color(this._colors.magenta)) + args.push(arg) + } else { + objs.push(arg) + } } - if (!encoding) encoding = 'utf8' - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) + args[0] = msg + objs.forEach(function (obj) { + args.push(obj) + }) - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) + // In IE/Edge console functions don't inherit from Function.prototype + // so this is necessary to get all the args applied. + Function.prototype.apply.apply(console.log, [console, args]) +} - case 'ascii': - return asciiSlice(this, start, end) +function color (color) { + return 'color: ' + color + ';' +} - case 'latin1': - case 'binary': - return latin1Slice(this, start, end) +function getTimeStamp () { + var date = new Date() + var hours = pad(date.getHours().toString()) + var minutes = pad(date.getMinutes().toString()) + var seconds = pad(date.getSeconds().toString()) + return hours + ':' + minutes + ':' + seconds +} - case 'base64': - return base64Slice(this, start, end) +function pad (str) { + return str.length !== 2 ? 0 + str : str +} - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) +},{"assert":37}],105:[function(require,module,exports){ +module.exports = LRU - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } +function LRU (opts) { + if (!(this instanceof LRU)) return new LRU(opts) + if (typeof opts === 'number') opts = {max: opts} + if (!opts) opts = {} + this.cache = {} + this.head = this.tail = null + this.length = 0 + this.max = opts.max || 1000 + this.maxAge = opts.maxAge || 0 } -// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) -// to detect a Buffer instance. It's not possible to use `instanceof Buffer` -// reliably in a browserify context because there could be multiple different -// copies of the 'buffer' package in use. This method works even for Buffer -// instances that were created from another copy of the `buffer` package. -// See: https://github.com/feross/buffer/issues/154 -Buffer.prototype._isBuffer = true +Object.defineProperty(LRU.prototype, 'keys', { + get: function () { return Object.keys(this.cache) } +}) -function swap (b, n, m) { - var i = b[n] - b[n] = b[m] - b[m] = i +LRU.prototype.clear = function () { + this.cache = {} + this.head = this.tail = null + this.length = 0 } -Buffer.prototype.swap16 = function swap16 () { - var len = this.length - if (len % 2 !== 0) { - throw new RangeError('Buffer size must be a multiple of 16-bits') - } - for (var i = 0; i < len; i += 2) { - swap(this, i, i + 1) - } - return this -} +LRU.prototype.remove = function (key) { + if (typeof key !== 'string') key = '' + key + if (!this.cache.hasOwnProperty(key)) return -Buffer.prototype.swap32 = function swap32 () { - var len = this.length - if (len % 4 !== 0) { - throw new RangeError('Buffer size must be a multiple of 32-bits') - } - for (var i = 0; i < len; i += 4) { - swap(this, i, i + 3) - swap(this, i + 1, i + 2) - } - return this + var element = this.cache[key] + delete this.cache[key] + this._unlink(key, element.prev, element.next) + return element.value } -Buffer.prototype.swap64 = function swap64 () { - var len = this.length - if (len % 8 !== 0) { - throw new RangeError('Buffer size must be a multiple of 64-bits') - } - for (var i = 0; i < len; i += 8) { - swap(this, i, i + 7) - swap(this, i + 1, i + 6) - swap(this, i + 2, i + 5) - swap(this, i + 3, i + 4) +LRU.prototype._unlink = function (key, prev, next) { + this.length-- + + if (this.length === 0) { + this.head = this.tail = null + } else { + if (this.head === key) { + this.head = prev + this.cache[this.head].next = null + } else if (this.tail === key) { + this.tail = next + this.cache[this.tail].prev = null + } else { + this.cache[prev].next = next + this.cache[next].prev = prev + } } - return this } -Buffer.prototype.toString = function toString () { - var length = this.length - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} +LRU.prototype.peek = function (key) { + if (!this.cache.hasOwnProperty(key)) return -Buffer.prototype.toLocaleString = Buffer.prototype.toString + var element = this.cache[key] -Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 + if (!this._checkAge(key, element)) return + return element.value } -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() - if (this.length > max) str += ' ... ' - return '' -} +LRU.prototype.set = function (key, value) { + if (typeof key !== 'string') key = '' + key -Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { - if (isInstance(target, Uint8Array)) { - target = Buffer.from(target, target.offset, target.byteLength) - } - if (!Buffer.isBuffer(target)) { - throw new TypeError( - 'The "target" argument must be one of type Buffer or Uint8Array. ' + - 'Received type ' + (typeof target) - ) - } + var element - if (start === undefined) { - start = 0 - } - if (end === undefined) { - end = target ? target.length : 0 - } - if (thisStart === undefined) { - thisStart = 0 - } - if (thisEnd === undefined) { - thisEnd = this.length - } + if (this.cache.hasOwnProperty(key)) { + element = this.cache[key] + element.value = value + if (this.maxAge) element.modified = Date.now() - if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { - throw new RangeError('out of range index') - } + // If it's already the head, there's nothing more to do: + if (key === this.head) return value + this._unlink(key, element.prev, element.next) + } else { + element = {value: value, modified: 0, next: null, prev: null} + if (this.maxAge) element.modified = Date.now() + this.cache[key] = element - if (thisStart >= thisEnd && start >= end) { - return 0 - } - if (thisStart >= thisEnd) { - return -1 - } - if (start >= end) { - return 1 + // Eviction is only possible if the key didn't already exist: + if (this.length === this.max) this.evict() } - start >>>= 0 - end >>>= 0 - thisStart >>>= 0 - thisEnd >>>= 0 + this.length++ + element.next = null + element.prev = this.head - if (this === target) return 0 + if (this.head) this.cache[this.head].next = key + this.head = key - var x = thisEnd - thisStart - var y = end - start - var len = Math.min(x, y) + if (!this.tail) this.tail = key + return value +} - var thisCopy = this.slice(thisStart, thisEnd) - var targetCopy = target.slice(start, end) +LRU.prototype._checkAge = function (key, element) { + if (this.maxAge && (Date.now() - element.modified) > this.maxAge) { + this.remove(key) + return false + } + return true +} - for (var i = 0; i < len; ++i) { - if (thisCopy[i] !== targetCopy[i]) { - x = thisCopy[i] - y = targetCopy[i] - break +LRU.prototype.get = function (key) { + if (typeof key !== 'string') key = '' + key + if (!this.cache.hasOwnProperty(key)) return + + var element = this.cache[key] + + if (!this._checkAge(key, element)) return + + if (this.head !== key) { + if (key === this.tail) { + this.tail = element.next + this.cache[this.tail].prev = null + } else { + // Set prev.next -> element.next: + this.cache[element.prev].next = element.next } + + // Set element.next.prev -> element.prev: + this.cache[element.next].prev = element.prev + + // Element is the new head + this.cache[this.head].next = key + element.prev = this.head + element.next = null + this.head = key } - if (x < y) return -1 - if (y < x) return 1 - return 0 + return element.value } -// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, -// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +LRU.prototype.evict = function () { + if (!this.tail) return + this.remove(this.tail) +} + +},{}],106:[function(require,module,exports){ +var assert = require('nanoassert') +var morph = require('./lib/morph') + +var TEXT_NODE = 3 +// var DEBUG = false + +module.exports = nanomorph + +// Morph one tree into another tree // -// Arguments: -// - buffer - a Buffer to search -// - val - a string, Buffer, or number -// - byteOffset - an index into `buffer`; will be clamped to an int32 -// - encoding - an optional encoding, relevant is val is a string -// - dir - true for indexOf, false for lastIndexOf -function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { - // Empty buffer means no match - if (buffer.length === 0) return -1 +// no parent +// -> same: diff and walk children +// -> not same: replace and return +// old node doesn't exist +// -> insert new node +// new node doesn't exist +// -> delete old node +// nodes are not the same +// -> diff nodes and apply patch to old node +// nodes are the same +// -> walk all child nodes and append to old node +function nanomorph (oldTree, newTree, options) { + // if (DEBUG) { + // console.log( + // 'nanomorph\nold\n %s\nnew\n %s', + // oldTree && oldTree.outerHTML, + // newTree && newTree.outerHTML + // ) + // } + assert.equal(typeof oldTree, 'object', 'nanomorph: oldTree should be an object') + assert.equal(typeof newTree, 'object', 'nanomorph: newTree should be an object') - // Normalize byteOffset - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset = +byteOffset // Coerce to Number. - if (numberIsNaN(byteOffset)) { - // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer - byteOffset = dir ? 0 : (buffer.length - 1) + if (options && options.childrenOnly) { + updateChildren(newTree, oldTree) + return oldTree } - // Normalize byteOffset: negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = buffer.length + byteOffset - if (byteOffset >= buffer.length) { - if (dir) return -1 - else byteOffset = buffer.length - 1 - } else if (byteOffset < 0) { - if (dir) byteOffset = 0 - else return -1 - } + assert.notEqual( + newTree.nodeType, + 11, + 'nanomorph: newTree should have one root node (which is not a DocumentFragment)' + ) - // Normalize val - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } + return walk(newTree, oldTree) +} - // Finally, search either indexOf (if dir is true) or lastIndexOf - if (Buffer.isBuffer(val)) { - // Special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(buffer, val, byteOffset, encoding, dir) - } else if (typeof val === 'number') { - val = val & 0xFF // Search for a byte value [0-255] - if (typeof Uint8Array.prototype.indexOf === 'function') { - if (dir) { - return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) - } else { - return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) - } - } - return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) +// Walk and morph a dom tree +function walk (newNode, oldNode) { + // if (DEBUG) { + // console.log( + // 'walk\nold\n %s\nnew\n %s', + // oldNode && oldNode.outerHTML, + // newNode && newNode.outerHTML + // ) + // } + if (!oldNode) { + return newNode + } else if (!newNode) { + return null + } else if (newNode.isSameNode && newNode.isSameNode(oldNode)) { + return oldNode + } else if (newNode.tagName !== oldNode.tagName || getComponentId(newNode) !== getComponentId(oldNode)) { + return newNode + } else { + morph(newNode, oldNode) + updateChildren(newNode, oldNode) + return oldNode } +} - throw new TypeError('val must be string, number or Buffer') +function getComponentId (node) { + return node.dataset ? node.dataset.nanomorphComponentId : undefined } -function arrayIndexOf (arr, val, byteOffset, encoding, dir) { - var indexSize = 1 - var arrLength = arr.length - var valLength = val.length +// Update the children of elements +// (obj, obj) -> null +function updateChildren (newNode, oldNode) { + // if (DEBUG) { + // console.log( + // 'updateChildren\nold\n %s\nnew\n %s', + // oldNode && oldNode.outerHTML, + // newNode && newNode.outerHTML + // ) + // } + var oldChild, newChild, morphed, oldMatch - if (encoding !== undefined) { - encoding = String(encoding).toLowerCase() - if (encoding === 'ucs2' || encoding === 'ucs-2' || - encoding === 'utf16le' || encoding === 'utf-16le') { - if (arr.length < 2 || val.length < 2) { - return -1 + // The offset is only ever increased, and used for [i - offset] in the loop + var offset = 0 + + for (var i = 0; ; i++) { + oldChild = oldNode.childNodes[i] + newChild = newNode.childNodes[i - offset] + // if (DEBUG) { + // console.log( + // '===\n- old\n %s\n- new\n %s', + // oldChild && oldChild.outerHTML, + // newChild && newChild.outerHTML + // ) + // } + // Both nodes are empty, do nothing + if (!oldChild && !newChild) { + break + + // There is no new child, remove old + } else if (!newChild) { + oldNode.removeChild(oldChild) + i-- + + // There is no old child, add new + } else if (!oldChild) { + oldNode.appendChild(newChild) + offset++ + + // Both nodes are the same, morph + } else if (same(newChild, oldChild)) { + morphed = walk(newChild, oldChild) + if (morphed !== oldChild) { + oldNode.replaceChild(morphed, oldChild) + offset++ } - indexSize = 2 - arrLength /= 2 - valLength /= 2 - byteOffset /= 2 - } - } - function read (buf, i) { - if (indexSize === 1) { - return buf[i] + // Both nodes do not share an ID or a placeholder, try reorder } else { - return buf.readUInt16BE(i * indexSize) - } - } + oldMatch = null - var i - if (dir) { - var foundIndex = -1 - for (i = byteOffset; i < arrLength; i++) { - if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return foundIndex * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 - } - } - } else { - if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength - for (i = byteOffset; i >= 0; i--) { - var found = true - for (var j = 0; j < valLength; j++) { - if (read(arr, i + j) !== read(val, j)) { - found = false + // Try and find a similar node somewhere in the tree + for (var j = i; j < oldNode.childNodes.length; j++) { + if (same(oldNode.childNodes[j], newChild)) { + oldMatch = oldNode.childNodes[j] break } } - if (found) return i - } - } - - return -1 -} - -Buffer.prototype.includes = function includes (val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1 -} -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, true) -} + // If there was a node with the same ID or placeholder in the old list + if (oldMatch) { + morphed = walk(newChild, oldMatch) + if (morphed !== oldMatch) offset++ + oldNode.insertBefore(morphed, oldChild) -Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, false) -} + // It's safe to morph two nodes in-place if neither has an ID + } else if (!newChild.id && !oldChild.id) { + morphed = walk(newChild, oldChild) + if (morphed !== oldChild) { + oldNode.replaceChild(morphed, oldChild) + offset++ + } -function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining + // Insert the node at the index if we couldn't morph or find a matching node + } else { + oldNode.insertBefore(newChild, oldChild) + offset++ + } } } - - var strLen = string.length - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; ++i) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (numberIsNaN(parsed)) return i - buf[offset + i] = parsed - } - return i -} - -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) } -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) +function same (a, b) { + if (a.id) return a.id === b.id + if (a.isSameNode) return a.isSameNode(b) + if (a.tagName !== b.tagName) return false + if (a.type === TEXT_NODE) return a.nodeValue === b.nodeValue + return false } -function latin1Write (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) -} +},{"./lib/morph":108,"nanoassert":93}],107:[function(require,module,exports){ +module.exports = [ + // attribute events (can be set with attributes) + 'onclick', + 'ondblclick', + 'onmousedown', + 'onmouseup', + 'onmouseover', + 'onmousemove', + 'onmouseout', + 'onmouseenter', + 'onmouseleave', + 'ontouchcancel', + 'ontouchend', + 'ontouchmove', + 'ontouchstart', + 'ondragstart', + 'ondrag', + 'ondragenter', + 'ondragleave', + 'ondragover', + 'ondrop', + 'ondragend', + 'onkeydown', + 'onkeypress', + 'onkeyup', + 'onunload', + 'onabort', + 'onerror', + 'onresize', + 'onscroll', + 'onselect', + 'onchange', + 'onsubmit', + 'onreset', + 'onfocus', + 'onblur', + 'oninput', + // other common events + 'oncontextmenu', + 'onfocusin', + 'onfocusout' +] -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} +},{}],108:[function(require,module,exports){ +var events = require('./events') +var eventsLength = events.length -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} +var ELEMENT_NODE = 1 +var TEXT_NODE = 3 +var COMMENT_NODE = 8 -Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset >>> 0 - if (isFinite(length)) { - length = length >>> 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - } else { - throw new Error( - 'Buffer.write(string, encoding, offset[, length]) is no longer supported' - ) - } +module.exports = morph - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining +// diff elements and apply the resulting patch to the old node +// (obj, obj) -> null +function morph (newNode, oldNode) { + var nodeType = newNode.nodeType + var nodeName = newNode.nodeName - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') + if (nodeType === ELEMENT_NODE) { + copyAttrs(newNode, oldNode) } - if (!encoding) encoding = 'utf8' - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) + if (nodeType === TEXT_NODE || nodeType === COMMENT_NODE) { + if (oldNode.nodeValue !== newNode.nodeValue) { + oldNode.nodeValue = newNode.nodeValue + } + } - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) + // Some DOM nodes are weird + // https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js + if (nodeName === 'INPUT') updateInput(newNode, oldNode) + else if (nodeName === 'OPTION') updateOption(newNode, oldNode) + else if (nodeName === 'TEXTAREA') updateTextarea(newNode, oldNode) - case 'ascii': - return asciiWrite(this, string, offset, length) + copyEvents(newNode, oldNode) +} - case 'latin1': - case 'binary': - return latin1Write(this, string, offset, length) +function copyAttrs (newNode, oldNode) { + var oldAttrs = oldNode.attributes + var newAttrs = newNode.attributes + var attrNamespaceURI = null + var attrValue = null + var fromValue = null + var attrName = null + var attr = null - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) + for (var i = newAttrs.length - 1; i >= 0; --i) { + attr = newAttrs[i] + attrName = attr.name + attrNamespaceURI = attr.namespaceURI + attrValue = attr.value + if (attrNamespaceURI) { + attrName = attr.localName || attrName + fromValue = oldNode.getAttributeNS(attrNamespaceURI, attrName) + if (fromValue !== attrValue) { + oldNode.setAttributeNS(attrNamespaceURI, attrName, attrValue) + } + } else { + if (!oldNode.hasAttribute(attrName)) { + oldNode.setAttribute(attrName, attrValue) + } else { + fromValue = oldNode.getAttribute(attrName) + if (fromValue !== attrValue) { + // apparently values are always cast to strings, ah well + if (attrValue === 'null' || attrValue === 'undefined') { + oldNode.removeAttribute(attrName) + } else { + oldNode.setAttribute(attrName, attrValue) + } + } + } + } + } - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) + // Remove any extra attributes found on the original DOM element that + // weren't found on the target element. + for (var j = oldAttrs.length - 1; j >= 0; --j) { + attr = oldAttrs[j] + if (attr.specified !== false) { + attrName = attr.name + attrNamespaceURI = attr.namespaceURI - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true + if (attrNamespaceURI) { + attrName = attr.localName || attrName + if (!newNode.hasAttributeNS(attrNamespaceURI, attrName)) { + oldNode.removeAttributeNS(attrNamespaceURI, attrName) + } + } else { + if (!newNode.hasAttributeNS(null, attrName)) { + oldNode.removeAttribute(attrName) + } + } } } } -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) +function copyEvents (newNode, oldNode) { + for (var i = 0; i < eventsLength; i++) { + var ev = events[i] + if (newNode[ev]) { // if new element has a whitelisted attribute + oldNode[ev] = newNode[ev] // update existing element + } else if (oldNode[ev]) { // if existing element has it and new one doesnt + oldNode[ev] = undefined // remove it from existing element + } } } -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } +function updateOption (newNode, oldNode) { + updateAttribute(newNode, oldNode, 'selected') } -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] +// The "value" attribute is special for the element since it sets the +// initial value. Changing the "value" attribute without changing the "value" +// property will have no effect since it is only used to the set the initial +// value. Similar for the "checked" attribute, and "disabled". +function updateInput (newNode, oldNode) { + var newValue = newNode.value + var oldValue = oldNode.value - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 + updateAttribute(newNode, oldNode, 'checked') + updateAttribute(newNode, oldNode, 'disabled') - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint + // The "indeterminate" property can not be set using an HTML attribute. + // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox + if (newNode.indeterminate !== oldNode.indeterminate) { + oldNode.indeterminate = newNode.indeterminate + } - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } + // Persist file value since file inputs can't be changed programatically + if (oldNode.type === 'file') return - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } + if (newValue !== oldValue) { + oldNode.setAttribute('value', newValue) + oldNode.value = newValue + } - res.push(codePoint) - i += bytesPerSequence + if (newValue === 'null') { + oldNode.value = '' + oldNode.removeAttribute('value') } - return decodeCodePointsArray(res) + if (!newNode.hasAttributeNS(null, 'value')) { + oldNode.removeAttribute('value') + } else if (oldNode.type === 'range') { + // this is so elements like slider move their UI thingy + oldNode.value = newValue + } } -// Based on http://stackoverflow.com/a/22747272/680742, the browser with -// the lowest limit is Chrome, with 0x10000 args. -// We go 1 magnitude less, for safety -var MAX_ARGUMENTS_LENGTH = 0x1000 - -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() +function updateTextarea (newNode, oldNode) { + var newValue = newNode.value + if (newValue !== oldNode.value) { + oldNode.value = newValue } - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) + if (oldNode.firstChild && oldNode.firstChild.nodeValue !== newValue) { + // Needed for IE. Apparently IE sets the placeholder as the + // node value and vise versa. This ignores an empty update. + if (newValue === '' && oldNode.firstChild.nodeValue === oldNode.placeholder) { + return + } + + oldNode.firstChild.nodeValue = newValue } - return res } -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i] & 0x7F) +function updateAttribute (newNode, oldNode, name) { + if (newNode[name] !== oldNode[name]) { + oldNode[name] = newNode[name] + if (newNode[name]) { + oldNode.setAttribute(name, '') + } else { + oldNode.removeAttribute(name) + } } - return ret } -function latin1Slice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) +},{"./events":107}],109:[function(require,module,exports){ +var reg = /([^?=&]+)(=([^&]*))?/g +var assert = require('assert') - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i]) - } - return ret -} +module.exports = qs -function hexSlice (buf, start, end) { - var len = buf.length +function qs (url) { + assert.equal(typeof url, 'string', 'nanoquery: url should be type string') - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len + var obj = {} + url.replace(/^.*\?/, '').replace(reg, function (a0, a1, a2, a3) { + var value = decodeURIComponent(a3) + var key = decodeURIComponent(a1) + if (obj.hasOwnProperty(key)) { + if (Array.isArray(obj[key])) obj[key].push(value) + else obj[key] = [obj[key], value] + } else { + obj[key] = value + } + }) - var out = '' - for (var i = start; i < end; ++i) { - out += toHex(buf[i]) - } - return out + return obj } -function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) - } - return res -} +},{"assert":93}],110:[function(require,module,exports){ +'use strict' -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end +var assert = require('assert') + +module.exports = nanoraf + +// Only call RAF when needed +// (fn, fn?) -> fn +function nanoraf (render, raf) { + assert.equal(typeof render, 'function', 'nanoraf: render should be a function') + assert.ok(typeof raf === 'function' || typeof raf === 'undefined', 'nanoraf: raf should be a function or undefined') + + if (!raf) raf = window.requestAnimationFrame + var redrawScheduled = false + var args = null + + return function frame () { + if (args === null && !redrawScheduled) { + redrawScheduled = true - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } + raf(function redraw () { + redrawScheduled = false - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } + var length = args.length + var _args = new Array(length) + for (var i = 0; i < length; i++) _args[i] = args[i] - if (end < start) end = start + render.apply(render, _args) + args = null + }) + } - var newBuf = this.subarray(start, end) - // Return an augmented `Uint8Array` instance - newBuf.__proto__ = Buffer.prototype - return newBuf + args = arguments + } } -/* - * Need to make sure that buffer isn't trying to write out of bounds. - */ -function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') -} +},{"assert":93}],111:[function(require,module,exports){ +var assert = require('assert') +var wayfarer = require('wayfarer') -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) +// electron support +var isLocalFile = (/file:\/\//.test( + typeof window === 'object' && + window.location && + window.location.origin +)) - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } +/* eslint-disable no-useless-escape */ +var electron = '^(file:\/\/|\/)(.*\.html?\/?)?' +var protocol = '^(http(s)?(:\/\/))?(www\.)?' +var domain = '[a-zA-Z0-9-_\.]+(:[0-9]{1,5})?(\/{1})?' +var qs = '[\?].*$' +/* eslint-enable no-useless-escape */ - return val -} +var stripElectron = new RegExp(electron) +var prefix = new RegExp(protocol + domain) +var normalize = new RegExp('#') +var suffix = new RegExp(qs) -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } +module.exports = Nanorouter - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } +function Nanorouter (opts) { + if (!(this instanceof Nanorouter)) return new Nanorouter(opts) + opts = opts || {} + this.router = wayfarer(opts.default || '/404') +} - return val +Nanorouter.prototype.on = function (routename, listener) { + assert.equal(typeof routename, 'string') + routename = routename.replace(/^[#/]/, '') + this.router.on(routename, listener) } -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] +Nanorouter.prototype.emit = function (routename) { + assert.equal(typeof routename, 'string') + routename = pathname(routename, isLocalFile) + return this.router.emit(routename) } -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) +Nanorouter.prototype.match = function (routename) { + assert.equal(typeof routename, 'string') + routename = pathname(routename, isLocalFile) + return this.router.match(routename) } -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] +// replace everything in a route but the pathname and hash +function pathname (routename, isElectron) { + if (isElectron) routename = routename.replace(stripElectron, '') + else routename = routename.replace(prefix, '') + return decodeURI(routename.replace(suffix, '').replace(normalize, '/')) } -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) +},{"assert":93,"wayfarer":132}],112:[function(require,module,exports){ +var assert = require('assert') - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) -} +var hasWindow = typeof window !== 'undefined' -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) +function createScheduler () { + var scheduler + if (hasWindow) { + if (!window._nanoScheduler) window._nanoScheduler = new NanoScheduler(true) + scheduler = window._nanoScheduler + } else { + scheduler = new NanoScheduler() + } + return scheduler +} - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) +function NanoScheduler (hasWindow) { + this.hasWindow = hasWindow + this.hasIdle = this.hasWindow && window.requestIdleCallback + this.method = this.hasIdle ? window.requestIdleCallback.bind(window) : this.setTimeout + this.scheduled = false + this.queue = [] } -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) +NanoScheduler.prototype.push = function (cb) { + assert.equal(typeof cb, 'function', 'nanoscheduler.push: cb should be type function') - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 + this.queue.push(cb) + this.schedule() +} - if (val >= mul) val -= Math.pow(2, 8 * byteLength) +NanoScheduler.prototype.schedule = function () { + if (this.scheduled) return - return val + this.scheduled = true + var self = this + this.method(function (idleDeadline) { + var cb + while (self.queue.length && idleDeadline.timeRemaining() > 0) { + cb = self.queue.shift() + cb(idleDeadline) + } + self.scheduled = false + if (self.queue.length) self.schedule() + }) } -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) +NanoScheduler.prototype.setTimeout = function (cb) { + setTimeout(cb, 0, { + timeRemaining: function () { + return 1 + } + }) +} - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 +module.exports = createScheduler - if (val >= mul) val -= Math.pow(2, 8 * byteLength) +},{"assert":93}],113:[function(require,module,exports){ +var scheduler = require('nanoscheduler')() +var assert = require('assert') - return val -} +var perf +nanotiming.disabled = true +try { + perf = window.performance + nanotiming.disabled = window.localStorage.DISABLE_NANOTIMING === 'true' || !perf.mark +} catch (e) { } -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) -} +module.exports = nanotiming -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} +function nanotiming (name) { + assert.equal(typeof name, 'string', 'nanotiming: name should be type string') -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} + if (nanotiming.disabled) return noop -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) + var uuid = (perf.now() * 10000).toFixed() % Number.MAX_SAFE_INTEGER + var startName = 'start-' + uuid + '-' + name + perf.mark(startName) - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) -} + function end (cb) { + var endName = 'end-' + uuid + '-' + name + perf.mark(endName) -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) + scheduler.push(function () { + var err = null + try { + var measureName = name + ' [' + uuid + ']' + perf.measure(measureName, startName, endName) + perf.clearMarks(startName) + perf.clearMarks(endName) + } catch (e) { err = e } + if (cb) cb(err, name) + }) + } - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) + end.uuid = uuid + return end } -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) +function noop (cb) { + if (cb) { + scheduler.push(function () { + cb(new Error('nanotiming: performance API unavailable')) + }) + } } -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) -} +},{"assert":93,"nanoscheduler":112}],114:[function(require,module,exports){ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) -} +'use strict'; +/* eslint-disable no-unused-vars */ +var getOwnPropertySymbols = Object.getOwnPropertySymbols; +var hasOwnProperty = Object.prototype.hasOwnProperty; +var propIsEnumerable = Object.prototype.propertyIsEnumerable; -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) -} +function toObject(val) { + if (val === null || val === undefined) { + throw new TypeError('Object.assign cannot be called with null or undefined'); + } -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') - if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') - if (offset + ext > buf.length) throw new RangeError('Index out of range') + return Object(val); } -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } +function shouldUseNative() { + try { + if (!Object.assign) { + return false; + } - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } + // Detect buggy property enumeration order in older V8 versions. - return offset + byteLength -} + // https://bugs.chromium.org/p/v8/issues/detail?id=4118 + var test1 = new String('abc'); // eslint-disable-line no-new-wrappers + test1[5] = 'de'; + if (Object.getOwnPropertyNames(test1)[0] === '5') { + return false; + } -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2['_' + String.fromCharCode(i)] = i; + } + var order2 = Object.getOwnPropertyNames(test2).map(function (n) { + return test2[n]; + }); + if (order2.join('') !== '0123456789') { + return false; + } - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test3 = {}; + 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join('') !== + 'abcdefghijklmnopqrst') { + return false; + } - return offset + byteLength + return true; + } catch (err) { + // We don't expect any of the above to throw, but better to be safe. + return false; + } } -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - this[offset] = (value & 0xff) - return offset + 1 -} +module.exports = shouldUseNative() ? Object.assign : function (target, source) { + var from; + var to = toObject(target); + var symbols; -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - return offset + 2 -} + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - return offset + 2 -} + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - return offset + 4 -} + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } + } -Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - return offset + 4 -} + return to; +}; -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - var limit = Math.pow(2, (8 * byteLength) - 1) +},{}],115:[function(require,module,exports){ +var assert = require('assert') - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } +module.exports = objectChangeCallsite - var i = 0 - var mul = 1 - var sub = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } +function objectChangeCallsite (target, callback) { + assert.equal(typeof target, 'object', 'object-change-callsite: target should be type object') + assert.equal(typeof callback, 'function', 'object-change-callsite: callback should be type function') - return offset + byteLength + return new Proxy(target, { + set: function (obj, prop, value) { + var err = new Error() + var trace = strip(err.stack) + callback(prop, value, trace) + obj[prop] = value + return true + }, + deleteProperty: function (target, prop) { + var err = new Error() + var trace = strip(err.stack) + callback(prop, undefined, trace) + if (prop in target) { + delete target[prop] + return true + } + return false + } + }) } -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - var limit = Math.pow(2, (8 * byteLength) - 1) +function strip (str) { + var arr = str.split('\n') + arr = arr.length > 2 ? arr.slice(2) : arr + arr[0] = arr[0].replace(/^ {4}at /, '') + return '\n' + arr.join('\n') +} - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } +},{"assert":37}],116:[function(require,module,exports){ +/* global MutationObserver */ +var document = require('global/document') +var window = require('global/window') +var assert = require('assert') +var watch = Object.create(null) +var KEY_ID = 'onloadid' + (new Date() % 9e6).toString(36) +var KEY_ATTR = 'data-' + KEY_ID +var INDEX = 0 - var i = byteLength - 1 - var mul = 1 - var sub = 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { - sub = 1 +if (window && window.MutationObserver) { + var observer = new MutationObserver(function (mutations) { + if (Object.keys(watch).length < 1) return + for (var i = 0; i < mutations.length; i++) { + if (mutations[i].attributeName === KEY_ATTR) { + eachAttr(mutations[i], turnon, turnoff) + continue + } + eachMutation(mutations[i].removedNodes, turnoff) + eachMutation(mutations[i].addedNodes, turnon) } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + }) + if (document.body) { + beginObserve(observer) + } else { + document.addEventListener('DOMContentLoaded', function (event) { + beginObserve(observer) + }) } - - return offset + byteLength } -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 +function beginObserve (observer) { + observer.observe(document.documentElement, { + childList: true, + subtree: true, + attributes: true, + attributeOldValue: true, + attributeFilter: [KEY_ATTR] + }) } -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - return offset + 2 +module.exports = function onload (el, on, off, caller) { + assert(document.body, 'on-load: will not work prior to DOMContentLoaded') + on = on || function () {} + off = off || function () {} + el.setAttribute(KEY_ATTR, 'o' + INDEX) + watch['o' + INDEX] = [on, off, 0, caller || onload.caller] + INDEX += 1 + return el } -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - return offset + 2 +module.exports.KEY_ATTR = KEY_ATTR +module.exports.KEY_ID = KEY_ID + +function turnon (index, el) { + if (watch[index][0] && watch[index][2] === 0) { + watch[index][0](el) + watch[index][2] = 1 + } } -Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - return offset + 4 +function turnoff (index, el) { + if (watch[index][1] && watch[index][2] === 1) { + watch[index][1](el) + watch[index][2] = 0 + } } -Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - return offset + 4 +function eachAttr (mutation, on, off) { + var newValue = mutation.target.getAttribute(KEY_ATTR) + if (sameOrigin(mutation.oldValue, newValue)) { + watch[newValue] = watch[mutation.oldValue] + return + } + if (watch[mutation.oldValue]) { + off(mutation.oldValue, mutation.target) + } + if (watch[newValue]) { + on(newValue, mutation.target) + } } -function checkIEEE754 (buf, value, offset, ext, max, min) { - if (offset + ext > buf.length) throw new RangeError('Index out of range') - if (offset < 0) throw new RangeError('Index out of range') +function sameOrigin (oldValue, newValue) { + if (!oldValue || !newValue) return false + return watch[oldValue][3] === watch[newValue][3] } -function writeFloat (buf, value, offset, littleEndian, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) +function eachMutation (nodes, fn) { + var keys = Object.keys(watch) + for (var i = 0; i < nodes.length; i++) { + if (nodes[i] && nodes[i].getAttribute && nodes[i].getAttribute(KEY_ATTR)) { + var onloadid = nodes[i].getAttribute(KEY_ATTR) + keys.forEach(function (k) { + if (onloadid === k) { + fn(k, nodes[i]) + } + }) + } + if (nodes[i].childNodes.length > 0) { + eachMutation(nodes[i].childNodes, fn) + } } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 } -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} +},{"assert":93,"global/document":64,"global/window":65}],117:[function(require,module,exports){ +var scheduler = require('nanoscheduler')() +var assert = require('assert') -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) -} +var entryTypes = [ + 'frame', + 'measure', + 'navigation', + 'resource', + 'longtask' +] -function writeDouble (buf, value, offset, littleEndian, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 -} +module.exports = onPerformance -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) -} +function onPerformance (cb) { + assert.equal(typeof cb, 'function', 'on-performance: cb should be type function') -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) -} + var PerformanceObserver = typeof window !== 'undefined' && window.PerformanceObserver + if (!PerformanceObserver) return -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start + // Enable singleton. + if (window._onperformance) { + window._onperformance.push(cb) + return stop + } - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 + window._onperformance = [cb] + var observer = new PerformanceObserver(parseEntries) + setTimeout(function () { + parseEntries(window.performance) + observer.observe({ entryTypes: entryTypes }) + }, 0) - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') + return stop + + function stop () { + window._onperformance.splice(window._onperformance.indexOf(cb), 1) } - if (start < 0 || start >= this.length) throw new RangeError('Index out of range') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start + function parseEntries (list) { + list.getEntries().forEach(function (entry) { + scheduler.push(function () { + clear(entry) + window._onperformance.forEach(function (cb) { + cb(entry) + }) + }) + }) } - var len = end - start + // Navigation, longtask and frame don't have a clear method (yet) + // Resource timings can only be cleared in bulk + // see: https://developer.mozilla.org/en-US/docs/Web/API/Performance/clearMeasures + function clear (entry) { + var type = entry.entryType + if (type === 'measure') window.performance.clearMeasures(entry.name) + else if (type === 'resource') window.performance.clearResourceTimings() + } +} - if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { - // Use built-in when available, missing from IE11 - this.copyWithin(targetStart, start, end) - } else if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (var i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } +},{"assert":93,"nanoscheduler":112}],118:[function(require,module,exports){ +(function (process){(function (){ +// Generated by CoffeeScript 1.12.2 +(function() { + var getNanoSeconds, hrtime, loadTime, moduleLoadTime, nodeLoadTime, upTime; + + if ((typeof performance !== "undefined" && performance !== null) && performance.now) { + module.exports = function() { + return performance.now(); + }; + } else if ((typeof process !== "undefined" && process !== null) && process.hrtime) { + module.exports = function() { + return (getNanoSeconds() - nodeLoadTime) / 1e6; + }; + hrtime = process.hrtime; + getNanoSeconds = function() { + var hr; + hr = hrtime(); + return hr[0] * 1e9 + hr[1]; + }; + moduleLoadTime = getNanoSeconds(); + upTime = process.uptime() * 1e9; + nodeLoadTime = moduleLoadTime - upTime; + } else if (Date.now) { + module.exports = function() { + return Date.now() - loadTime; + }; + loadTime = Date.now(); } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, end), - targetStart - ) + module.exports = function() { + return new Date().getTime() - loadTime; + }; + loadTime = new Date().getTime(); } - return len -} +}).call(this); -// Usage: -// buffer.fill(number[, offset[, end]]) -// buffer.fill(buffer[, offset[, end]]) -// buffer.fill(string[, offset[, end]][, encoding]) -Buffer.prototype.fill = function fill (val, start, end, encoding) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - encoding = start - start = 0 - end = this.length - } else if (typeof end === 'string') { - encoding = end - end = this.length - } - if (encoding !== undefined && typeof encoding !== 'string') { - throw new TypeError('encoding must be a string') - } - if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - if (val.length === 1) { - var code = val.charCodeAt(0) - if ((encoding === 'utf8' && code < 128) || - encoding === 'latin1') { - // Fast path: If `val` fits into a single byte, use that numeric value. - val = code - } - } - } else if (typeof val === 'number') { - val = val & 255 - } - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } - if (end <= start) { - return this - } +}).call(this)}).call(this,require('_process')) +},{"_process":121}],119:[function(require,module,exports){ +module.exports = plucker - start = start >>> 0 - end = end === undefined ? this.length : end >>> 0 +function plucker(path, object) { + return arguments.length >= 2 + ? pluck(path)(object) + : pluck(path) +} - if (!val) val = 0 +function pluck(path) { + path = typeof path === 'string' + ? String(path).trim().split('.') + : path - var i - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val - } + if (path.length < 2) { + path = path[0] + return pluckSingle } else { - var bytes = Buffer.isBuffer(val) - ? val - : Buffer.from(val, encoding) - var len = bytes.length - if (len === 0) { - throw new TypeError('The value "' + val + - '" is invalid for argument "value"') - } - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len] - } + var l = path.length + return pluckPath } - return this -} + function pluckSingle(object) { + return object[path] + } -// HELPER FUNCTIONS -// ================ + function pluckPath(object) { + for (var i = 0; i < l; i++) { + if (typeof object === 'undefined') break -var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g + object = object[path[i]] + } -function base64clean (str) { - // Node takes equal signs as end of the Base64 encoding - str = str.split('=')[0] - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = str.trim().replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' + return object } - return str } -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) -} +},{}],120:[function(require,module,exports){ +module.exports = prettierBytes -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] +function prettierBytes (num) { + if (typeof num !== 'number' || isNaN(num)) { + throw new TypeError('Expected a number, got ' + typeof num) + } - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i) + var neg = num < 0 + var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } + if (neg) { + num = -num + } - // valid lead - leadSurrogate = codePoint + if (num < 1) { + return (neg ? '-' : '') + num + ' B' + } - continue - } + var exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1) + num = Number(num / Math.pow(1000, exponent)) + var unit = units[exponent] - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } + if (num >= 10 || num % 1 === 0) { + // Do not show decimals when the number is two-digit, or if the number has no + // decimal component. + return (neg ? '-' : '') + num.toFixed(0) + ' ' + unit + } else { + return (neg ? '-' : '') + num.toFixed(1) + ' ' + unit + } +} - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } +},{}],121:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; - leadSurrogate = null +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } +var cachedSetTimeout; +var cachedClearTimeout; - return bytes +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); } - -function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); } +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - return byteArray } +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) -} -function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i -} -// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass -// the `instanceof` check but they should be treated as of that type. -// See: https://github.com/feross/buffer/issues/166 -function isInstance (obj, type) { - return obj instanceof type || - (obj != null && obj.constructor != null && obj.constructor.name != null && - obj.constructor.name === type.name) } -function numberIsNaN (obj) { - // For IE11 support - return obj !== obj // eslint-disable-line no-self-compare +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } } -}).call(this,require("buffer").Buffer) -},{"base64-js":129,"buffer":131,"ieee754":133}],132:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; -var objectCreate = Object.create || objectCreatePolyfill -var objectKeys = Object.keys || objectKeysPolyfill -var bind = Function.prototype.bind || functionBindPolyfill + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} -function EventEmitter() { - if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) { - this._events = objectCreate(null); - this._eventsCount = 0; - } +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; - this._maxListeners = this._maxListeners || undefined; +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; } -module.exports = EventEmitter; +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; +function noop() {} -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -var defaultMaxListeners = 10; +process.listeners = function (name) { return [] } -var hasDefineProperty; -try { - var o = {}; - if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 }); - hasDefineProperty = o.x === 0; -} catch (err) { hasDefineProperty = false } -if (hasDefineProperty) { - Object.defineProperty(EventEmitter, 'defaultMaxListeners', { - enumerable: true, - get: function() { - return defaultMaxListeners; - }, - set: function(arg) { - // check whether the input is a positive number (whose value is zero or - // greater and not a NaN). - if (typeof arg !== 'number' || arg < 0 || arg !== arg) - throw new TypeError('"defaultMaxListeners" must be a positive number'); - defaultMaxListeners = arg; - } - }); -} else { - EventEmitter.defaultMaxListeners = defaultMaxListeners; -} +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { - if (typeof n !== 'number' || n < 0 || isNaN(n)) - throw new TypeError('"n" argument must be a positive number'); - this._maxListeners = n; - return this; +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); }; +process.umask = function() { return 0; }; -function $getMaxListeners(that) { - if (that._maxListeners === undefined) - return EventEmitter.defaultMaxListeners; - return that._maxListeners; -} +},{}],122:[function(require,module,exports){ +var inherits = require('inherits') +var EventEmitter = require('events').EventEmitter +var now = require('right-now') +var raf = require('raf') -EventEmitter.prototype.getMaxListeners = function getMaxListeners() { - return $getMaxListeners(this); -}; +module.exports = Engine +function Engine(fn) { + if (!(this instanceof Engine)) + return new Engine(fn) + this.running = false + this.last = now() + this._frame = 0 + this._tick = this.tick.bind(this) -// These standalone emit* functions are used to optimize calling of event -// handlers for fast cases because emit() itself often has a variable number of -// arguments and can be deoptimized because of that. These functions always have -// the same number of arguments and thus do not get deoptimized, so the code -// inside them can execute faster. -function emitNone(handler, isFn, self) { - if (isFn) - handler.call(self); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self); - } -} -function emitOne(handler, isFn, self, arg1) { - if (isFn) - handler.call(self, arg1); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self, arg1); - } + if (fn) + this.on('tick', fn) } -function emitTwo(handler, isFn, self, arg1, arg2) { - if (isFn) - handler.call(self, arg1, arg2); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self, arg1, arg2); - } + +inherits(Engine, EventEmitter) + +Engine.prototype.start = function() { + if (this.running) + return + this.running = true + this.last = now() + this._frame = raf(this._tick) + return this } -function emitThree(handler, isFn, self, arg1, arg2, arg3) { - if (isFn) - handler.call(self, arg1, arg2, arg3); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self, arg1, arg2, arg3); - } + +Engine.prototype.stop = function() { + this.running = false + if (this._frame !== 0) + raf.cancel(this._frame) + this._frame = 0 + return this } -function emitMany(handler, isFn, self, args) { - if (isFn) - handler.apply(self, args); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].apply(self, args); - } +Engine.prototype.tick = function() { + this._frame = raf(this._tick) + var time = now() + var dt = time - this.last + this.emit('tick', dt) + this.last = time } +},{"events":43,"inherits":91,"raf":123,"right-now":126}],123:[function(require,module,exports){ +(function (global){(function (){ +var now = require('performance-now') + , root = typeof window === 'undefined' ? global : window + , vendors = ['moz', 'webkit'] + , suffix = 'AnimationFrame' + , raf = root['request' + suffix] + , caf = root['cancel' + suffix] || root['cancelRequest' + suffix] -EventEmitter.prototype.emit = function emit(type) { - var er, handler, len, args, i, events; - var doError = (type === 'error'); +for(var i = 0; !raf && i < vendors.length; i++) { + raf = root[vendors[i] + 'Request' + suffix] + caf = root[vendors[i] + 'Cancel' + suffix] + || root[vendors[i] + 'CancelRequest' + suffix] +} - events = this._events; - if (events) - doError = (doError && events.error == null); - else if (!doError) - return false; +// Some versions of FF have rAF but not cAF +if(!raf || !caf) { + var last = 0 + , id = 0 + , queue = [] + , frameDuration = 1000 / 60 - // If there is no 'error' event listener then throw. - if (doError) { - if (arguments.length > 1) - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Unhandled "error" event. (' + er + ')'); - err.context = er; - throw err; + raf = function(callback) { + if(queue.length === 0) { + var _now = now() + , next = Math.max(0, frameDuration - (_now - last)) + last = next + _now + setTimeout(function() { + var cp = queue.slice(0) + // Clear queue here to prevent + // callbacks from appending listeners + // to the current frame's queue + queue.length = 0 + for(var i = 0; i < cp.length; i++) { + if(!cp[i].cancelled) { + try{ + cp[i].callback(last) + } catch(e) { + setTimeout(function() { throw e }, 0) + } + } + } + }, Math.round(next)) } - return false; + queue.push({ + handle: ++id, + callback: callback, + cancelled: false + }) + return id } - handler = events[type]; - - if (!handler) - return false; - - var isFn = typeof handler === 'function'; - len = arguments.length; - switch (len) { - // fast cases - case 1: - emitNone(handler, isFn, this); - break; - case 2: - emitOne(handler, isFn, this, arguments[1]); - break; - case 3: - emitTwo(handler, isFn, this, arguments[1], arguments[2]); - break; - case 4: - emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); - break; - // slower - default: - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - emitMany(handler, isFn, this, args); + caf = function(handle) { + for(var i = 0; i < queue.length; i++) { + if(queue[i].handle === handle) { + queue[i].cancelled = true + } + } } +} - return true; -}; - -function _addListener(target, type, listener, prepend) { - var m; - var events; - var existing; - - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); - - events = target._events; - if (!events) { - events = target._events = objectCreate(null); - target._eventsCount = 0; - } else { - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (events.newListener) { - target.emit('newListener', type, - listener.listener ? listener.listener : listener); - - // Re-assign `events` because a newListener handler could have caused the - // this._events to be assigned to a new object - events = target._events; - } - existing = events[type]; +module.exports = function(fn) { + // Wrap in a new function to prevent + // `cancel` potentially being assigned + // to the native rAF function + return raf.call(root, fn) +} +module.exports.cancel = function() { + caf.apply(root, arguments) +} +module.exports.polyfill = function(object) { + if (!object) { + object = root; } + object.requestAnimationFrame = raf + object.cancelAnimationFrame = caf +} - if (!existing) { - // Optimize the case of one listener. Don't need the extra array object. - existing = events[type] = listener; - ++target._eventsCount; - } else { - if (typeof existing === 'function') { - // Adding the second element, need to change to array. - existing = events[type] = - prepend ? [listener, existing] : [existing, listener]; - } else { - // If we've already got an array, just append. - if (prepend) { - existing.unshift(listener); - } else { - existing.push(listener); - } - } +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"performance-now":118}],124:[function(require,module,exports){ +(function(U,X){"object"===typeof exports&&"undefined"!==typeof module?module.exports=X():"function"===typeof define&&define.amd?define(X):U.createREGL=X()})(this,function(){function U(a,b){this.id=Eb++;this.type=a;this.data=b}function X(a){if(0===a.length)return[];var b=a.charAt(0),c=a.charAt(a.length-1);if(1>>=b;c=(255>>=c;b|=c;c=(15>>=c;b|=c;c=(3>>c>>1}function hb(){function a(a){a:{for(var b=16;268435456>=b;b*=16)if(a<=b){a=b;break a}a=0}b=c[gb(a)>>2];return 0>2].push(a)}var c=J(8,function(){return[]});return{alloc:a,free:b,allocType:function(b,c){var d=null;switch(b){case 5120:d=new Int8Array(a(c),0,c);break;case 5121:d=new Uint8Array(a(c),0,c);break;case 5122:d=new Int16Array(a(2*c),0,c);break;case 5123:d=new Uint16Array(a(2*c),0,c);break;case 5124:d=new Int32Array(a(4*c),0,c);break;case 5125:d=new Uint32Array(a(4*c),0,c);break;case 5126:d=new Float32Array(a(4*c),0,c);break;default:return null}return d.length!== +c?d.subarray(0,c):d},freeType:function(a){b(a.buffer)}}}function da(a){return!!a&&"object"===typeof a&&Array.isArray(a.shape)&&Array.isArray(a.stride)&&"number"===typeof a.offset&&a.shape.length===a.stride.length&&(Array.isArray(a.data)||M(a.data))}function ib(a,b,c,e,f,d){for(var p=0;pd&&(d=e.buffer.byteLength,5123===m?d>>=1:5125===m&&(d>>=2));e.vertCount=d;d=h;0>h&&(d=4,h=e.buffer.dimension,1===h&&(d=0),2===h&&(d=1),3===h&&(d=4));e.primType=d}function p(a){e.elementsCount--;delete n[a.id];a.buffer.destroy();a.buffer=null}var n={},u=0,t={uint8:5121,uint16:5123};b.oes_element_index_uint&&(t.uint32=5125);f.prototype.bind=function(){this.buffer.bind()};var w=[];return{create:function(a, +b){function l(a){if(a)if("number"===typeof a)h(a),g.primType=4,g.vertCount=a|0,g.type=5121;else{var b=null,c=35044,e=-1,f=-1,k=0,n=0;if(Array.isArray(a)||M(a)||da(a))b=a;else if("data"in a&&(b=a.data),"usage"in a&&(c=ob[a.usage]),"primitive"in a&&(e=Ta[a.primitive]),"count"in a&&(f=a.count|0),"type"in a&&(n=t[a.type]),"length"in a)k=a.length|0;else if(k=f,5123===n||5122===n)k*=2;else if(5125===n||5124===n)k*=4;d(g,b,c,e,f,k,n)}else h(),g.primType=4,g.vertCount=0,g.type=5121;return l}var h=c.create(null, +34963,!0),g=new f(h._buffer);e.elementsCount++;l(a);l._reglType="elements";l._elements=g;l.subdata=function(a,b){h.subdata(a,b);return l};l.destroy=function(){p(g)};return l},createStream:function(a){var b=w.pop();b||(b=new f(c.create(null,34963,!0,!1)._buffer));d(b,a,35040,-1,-1,0,0);return b},destroyStream:function(a){w.push(a)},getElements:function(a){return"function"===typeof a&&a._elements instanceof f?a._elements:null},clear:function(){S(n).forEach(p)}}}function pb(a){for(var b=E.allocType(5123, +a.length),c=0;c>>31<<15,d=(e<<1>>>24)-127,e=e>>13&1023;b[c]=-24>d?f:-14>d?f+(e+1024>>-14-d):15>=e,c.height>>=e,B(c,g[e]),a.mipmask|=1<b;++b)a.images[b]=null;return a}function nb(a){for(var b=a.images,c=0;cb){for(var c=0;c=--this.refCount&&D(this)}});p.profile&&(d.getTotalTextureSize=function(){var a=0;Object.keys(ia).forEach(function(b){a+=ia[b].stats.size});return a});return{create2D:function(b,c){function e(a,b){var c=f.texInfo;Z.call(c);var g=Ha();"number"===typeof a?"number"===typeof b?r(g,a|0,b|0):r(g,a|0,a|0):a?(G(c,a),m(g,a)):r(g,1,1);c.genMipmaps&&(g.mipmask=(g.width<<1)-1);f.mipmask=g.mipmask;u(f, +g);f.internalformat=g.internalformat;e.width=g.width;e.height=g.height;xa(f);z(g,3553);H(c,3553);ya();nb(g);p.profile&&(f.stats.size=Ja(f.internalformat,f.type,g.width,g.height,c.genMipmaps,!1));e.format=aa[f.internalformat];e.type=K[f.type];e.mag=fa[c.magFilter];e.min=Da[c.minFilter];e.wrapS=ua[c.wrapS];e.wrapT=ua[c.wrapT];return e}var f=new O(3553);ia[f.id]=f;d.textureCount++;e(b,c);e.subimage=function(a,b,c,d){b|=0;c|=0;d|=0;var m=h();u(m,f);m.width=0;m.height=0;B(m,a);m.width=m.width||(f.width>> +d)-b;m.height=m.height||(f.height>>d)-c;xa(f);l(m,3553,b,c,d);ya();g(m);return e};e.resize=function(b,c){var g=b|0,d=c|0||g;if(g===f.width&&d===f.height)return e;e.width=f.width=g;e.height=f.height=d;xa(f);for(var h=0;f.mipmask>>h;++h){var m=g>>h,x=d>>h;if(!m||!x)break;a.texImage2D(3553,h,f.format,m,x,0,f.format,f.type,null)}ya();p.profile&&(f.stats.size=Ja(f.internalformat,f.type,g,d,!1,!1));return e};e._reglType="texture2d";e._texture=f;p.profile&&(e.stats=f.stats);e.destroy=function(){f.decRef()}; +return e},createCube:function(b,c,e,f,q,n){function k(a,b,c,g,e,d){var f,ca=y.texInfo;Z.call(ca);for(f=0;6>f;++f)D[f]=Ha();if("number"===typeof a||!a)for(a=a|0||1,f=0;6>f;++f)r(D[f],a,a);else if("object"===typeof a)if(b)m(D[0],a),m(D[1],b),m(D[2],c),m(D[3],g),m(D[4],e),m(D[5],d);else if(G(ca,a),t(y,a),"faces"in a)for(a=a.faces,f=0;6>f;++f)u(D[f],y),m(D[f],a[f]);else for(f=0;6>f;++f)m(D[f],a);u(y,D[0]);y.mipmask=ca.genMipmaps?(D[0].width<<1)-1:D[0].mipmask;y.internalformat=D[0].internalformat;k.width= +D[0].width;k.height=D[0].height;xa(y);for(f=0;6>f;++f)z(D[f],34069+f);H(ca,34067);ya();p.profile&&(y.stats.size=Ja(y.internalformat,y.type,k.width,k.height,ca.genMipmaps,!0));k.format=aa[y.internalformat];k.type=K[y.type];k.mag=fa[ca.magFilter];k.min=Da[ca.minFilter];k.wrapS=ua[ca.wrapS];k.wrapT=ua[ca.wrapT];for(f=0;6>f;++f)nb(D[f]);return k}var y=new O(34067);ia[y.id]=y;d.cubeCount++;var D=Array(6);k(b,c,e,f,q,n);k.subimage=function(a,b,c,e,f){c|=0;e|=0;f|=0;var d=h();u(d,y);d.width=0;d.height=0; +B(d,b);d.width=d.width||(y.width>>f)-c;d.height=d.height||(y.height>>f)-e;xa(y);l(d,34069+a,c,e,f);ya();g(d);return k};k.resize=function(b){b|=0;if(b!==y.width){k.width=y.width=b;k.height=y.height=b;xa(y);for(var c=0;6>c;++c)for(var g=0;y.mipmask>>g;++g)a.texImage2D(34069+c,g,y.format,b>>g,b>>g,0,y.format,y.type,null);ya();p.profile&&(y.stats.size=Ja(y.internalformat,y.type,k.width,k.height,!1,!0));return k}};k._reglType="textureCube";k._texture=y;p.profile&&(k.stats=y.stats);k.destroy=function(){y.decRef()}; +return k},clear:function(){for(var b=0;bc;++c)if(0!==(b.mipmask&1<>c,b.height>>c,0,b.internalformat, +b.type,null);else for(var g=0;6>g;++g)a.texImage2D(34069+g,c,b.internalformat,b.width>>c,b.height>>c,0,b.internalformat,b.type,null);H(b.texInfo,b.target)})},refresh:function(){for(var b=0;bg;++g){for(r= +0;ra;++a)c[a].resize(g);b.width=b.height=g;return b},_reglType:"framebufferCube",destroy:function(){c.forEach(function(a){a.destroy()})}})},clear:function(){S(H).forEach(q)}, +restore:function(){z.cur=null;z.next=null;z.dirty=!0;S(H).forEach(function(b){b.framebuffer=a.createFramebuffer();r(b)})}})}function Za(){this.w=this.z=this.y=this.x=this.state=0;this.buffer=null;this.size=0;this.normalized=!1;this.type=5126;this.divisor=this.stride=this.offset=0}function Sb(a,b,c,e,f){function d(a){if(a!==h.currentVAO){var c=b.oes_vertex_array_object;a?c.bindVertexArrayOES(a.vao):c.bindVertexArrayOES(null);h.currentVAO=a}}function p(c){if(c!==h.currentVAO){if(c)c.bindAttrs();else for(var e= +b.angle_instanced_arrays,f=0;f= +l.byteLength?n.subdata(l):(n.destroy(),c.buffers[d]=null));c.buffers[d]||(n=c.buffers[d]=f.create(h,34962,!1,!0));k.buffer=f.getBuffer(n);k.size=k.buffer.dimension|0;k.normalized=!1;k.type=k.buffer.dtype;k.offset=0;k.stride=0;k.divisor=0;k.state=1;g[d]=1}else f.getBuffer(h)?(k.buffer=f.getBuffer(h),k.size=k.buffer.dimension|0,k.normalized=!1,k.type=k.buffer.dtype,k.offset=0,k.stride=0,k.divisor=0,k.state=1):f.getBuffer(h.buffer)?(k.buffer=f.getBuffer(h.buffer),k.size=(+h.size||k.buffer.dimension)| +0,k.normalized=!!h.normalized||!1,k.type="type"in h?Ia[h.type]:k.buffer.dtype,k.offset=(h.offset||0)|0,k.stride=(h.stride||0)|0,k.divisor=(h.divisor||0)|0,k.state=1):"x"in h&&(k.x=+h.x||0,k.y=+h.y||0,k.z=+h.z||0,k.w=+h.w||0,k.state=2)}for(a=0;aa&&(a=b.stats.uniformsCount)}); +return a},c.getMaxAttributesCount=function(){var a=0;B.forEach(function(b){b.stats.attributesCount>a&&(a=b.stats.attributesCount)});return a});return{clear:function(){var b=a.deleteShader.bind(a);S(t).forEach(b);t={};S(w).forEach(b);w={};B.forEach(function(b){a.deleteProgram(b.program)});B.length=0;k={};c.shaderCount=0},program:function(b,e,d,f){var l=k[e];l||(l=k[e]={});var p=l[b];if(p&&(p.refCount++,!f))return p;var v=new n(e,b);c.shaderCount++;u(v,d,f);p||(l[b]=v);B.push(v);return A(v,{destroy:function(){v.refCount--; +if(0>=v.refCount){a.deleteProgram(v.program);var b=B.indexOf(v);B.splice(b,1);c.shaderCount--}0>=l[v.vertId].refCount&&(a.deleteShader(w[v.vertId]),delete w[v.vertId],delete k[v.fragId][v.vertId]);Object.keys(k[v.fragId]).length||(a.deleteShader(t[v.fragId]),delete t[v.fragId],delete k[v.fragId])}})},restore:function(){t={};w={};for(var a=0;a"+b+"?"+e+".constant["+b+"]:0;"}).join(""),"}}else{", +"if(",x,"(",e,".buffer)){",k,"=",f,".createStream(",34962,",",e,".buffer);","}else{",k,"=",f,".getBuffer(",e,".buffer);","}",l,'="type" in ',e,"?",g.glTypes,"[",e,".type]:",k,".dtype;",h.normalized,"=!!",e,".normalized;");d("size");d("offset");d("stride");d("divisor");c("}}");c.exit("if(",h.isStream,"){",f,".destroyStream(",k,");","}");return h})});return g}function D(a,b){var c=a["static"],d=a.dynamic;if("vao"in c){var e=c.vao;null!==e&&null===t.getVAO(e)&&(e=t.createVAO(e));return v(function(a){return a.link(t.getVAO(e))})}if("vao"in +d){var f=d.vao;return L(f,function(a,b){var c=a.invoke(b,f);return b.def(a.shared.vao+".getVAO("+c+")")})}return null}function y(a){var b=a["static"],c=a.dynamic,d={};Object.keys(b).forEach(function(a){var c=b[a];d[a]=v(function(a,b){return"number"===typeof c||"boolean"===typeof c?""+c:a.link(c)})});Object.keys(c).forEach(function(a){var b=c[a];d[a]=L(b,function(a,c){return a.invoke(c,b)})});return d}function la(a,b,d,e,f){function h(a){var b=m[a];b&&($a[a]=b)}var k=Z(a,b),l=E(a,f),m=F(a,l,f),n=H(a, +f),$a=O(a,f),p=G(a,f,k);h("viewport");h(g("scissor.box"));var q=0>1)",t],");")}function b(){c(w,".drawArraysInstancedANGLE(", +[p,r,q,t],");")}n?B?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")):b()}function g(){function a(){c(k+".drawElements("+[p,q,u,r+"<<(("+u+"-5121)>>1)"]+");")}function b(){c(k+".drawArrays("+[p,r,q]+");")}n?B?a():(c("if(",n,"){"),a(),c("}else{"),b(),c("}")):b()}var h=a.shared,k=h.gl,l=h.draw,m=d.draw,n=function(){var e=m.elements,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(l,".","elements");e&&f("if("+e+")"+k+".bindBuffer(34963,"+e+".buffer.buffer);");return e}(), +p=e("primitive"),r=e("offset"),q=function(){var e=m.count,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(l,".","count");return e}();if("number"===typeof q){if(0===q)return}else c("if(",q,"){"),c.exit("}");var t,w;oa&&(t=e("instances"),w=a.instancing);var u=n+".type",B=m.elements&&sa(m.elements);oa&&("number"!==typeof t||0<=t)?"string"===typeof t?(c("if(",t,">0){"),f(),c("}else if(",t,"<0){"),g(),c("}")):f():g()}function X(a,b,c,d,e){b=m();e=b.proc("body",e); +oa&&(b.instancing=e.def(b.shared.extensions,".angle_instanced_arrays"));a(b,e,c,d);return b.compile().body}function fa(a,b,c,d){C(a,b);c.useVAO?c.drawVAO?b(a.shared.vao,".setVAO(",c.drawVAO.append(a,b),");"):b(a.shared.vao,".setVAO(",a.shared.vao,".targetVAO);"):(b(a.shared.vao,".setVAO(null);"),U(a,b,c,d.attributes,function(){return!0}));ta(a,b,c,d.uniforms,function(){return!0});aa(a,b,b,c)}function Da(a,b){var c=a.proc("draw",1);C(a,c);V(a,c,b.context);R(a,c,b.framebuffer);T(a,c,b);N(a,c,b.state); +Q(a,c,b,!1,!0);var d=b.shader.progVar.append(a,c);c(a.shared.gl,".useProgram(",d,".program);");if(b.shader.program)fa(a,c,b,b.shader.program);else{c(a.shared.vao,".setVAO(null);");var e=a.global.def("{}"),f=c.def(d,".id"),g=c.def(e,"[",f,"]");c(a.cond(g).then(g,".call(this,a0);")["else"](g,"=",e,"[",f,"]=",a.link(function(c){return X(fa,a,b,c,1)}),"(",d,");",g,".call(this,a0);"))}0=--this.refCount&&p(this)};f.profile&&(e.getTotalRenderbufferSize=function(){var a=0;Object.keys(w).forEach(function(b){a+=w[b].stats.size});return a});return{create:function(b,c){function l(b,c){var d=0,e=0,k=32854; +"object"===typeof b&&b?("shape"in b?(e=b.shape,d=e[0]|0,e=e[1]|0):("radius"in b&&(d=e=b.radius|0),"width"in b&&(d=b.width|0),"height"in b&&(e=b.height|0)),"format"in b&&(k=n[b.format])):"number"===typeof b?(d=b|0,e="number"===typeof c?c|0:d):b||(d=e=1);if(d!==h.width||e!==h.height||k!==h.format)return l.width=h.width=d,l.height=h.height=e,h.format=k,a.bindRenderbuffer(36161,h.renderbuffer),a.renderbufferStorage(36161,k,d,e),f.profile&&(h.stats.size=T[h.format]*h.width*h.height),l.format=u[h.format], +l}var h=new d(a.createRenderbuffer());w[h.id]=h;e.renderbufferCount++;l(b,c);l.resize=function(b,c){var d=b|0,e=c|0||d;if(d===h.width&&e===h.height)return l;l.width=h.width=d;l.height=h.height=e;a.bindRenderbuffer(36161,h.renderbuffer);a.renderbufferStorage(36161,h.format,d,e);f.profile&&(h.stats.size=T[h.format]*h.width*h.height);return l};l._reglType="renderbuffer";l._renderbuffer=h;f.profile&&(l.stats=h.stats);l.destroy=function(){h.decRef()};return l},clear:function(){S(w).forEach(p)},restore:function(){S(w).forEach(function(b){b.renderbuffer= +a.createRenderbuffer();a.bindRenderbuffer(36161,b.renderbuffer);a.renderbufferStorage(36161,b.format,b.width,b.height)});a.bindRenderbuffer(36161,null)}}},Ya=[];Ya[6408]=4;Ya[6407]=3;var Pa=[];Pa[5121]=1;Pa[5126]=4;Pa[36193]=2;var Ba=["x","y","z","w"],Xb="blend.func blend.equation stencil.func stencil.opFront stencil.opBack sample.coverage viewport scissor.box polygonOffset.offset".split(" "),Ea={0:0,1:1,zero:0,one:1,"src color":768,"one minus src color":769,"src alpha":770,"one minus src alpha":771, +"dst color":774,"one minus dst color":775,"dst alpha":772,"one minus dst alpha":773,"constant color":32769,"one minus constant color":32770,"constant alpha":32771,"one minus constant alpha":32772,"src alpha saturate":776},ab={never:512,less:513,"<":513,equal:514,"=":514,"==":514,"===":514,lequal:515,"<=":515,greater:516,">":516,notequal:517,"!=":517,"!==":517,gequal:518,">=":518,always:519},Ra={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056, +invert:5386},Ab={cw:2304,ccw:2305},Bb=new K(!1,!1,!1,function(){}),$b=function(a,b){function c(){this.endQueryIndex=this.startQueryIndex=-1;this.sum=0;this.stats=null}function e(a,b,d){var e=p.pop()||new c;e.startQueryIndex=a;e.endQueryIndex=b;e.sum=0;e.stats=d;n.push(e)}if(!b.ext_disjoint_timer_query)return null;var f=[],d=[],p=[],n=[],u=[],t=[];return{beginQuery:function(a){var c=f.pop()||b.ext_disjoint_timer_query.createQueryEXT();b.ext_disjoint_timer_query.beginQueryEXT(35007,c);d.push(c);e(d.length- +1,d.length,a)},endQuery:function(){b.ext_disjoint_timer_query.endQueryEXT(35007)},pushScopeStats:e,update:function(){var a,c;a=d.length;if(0!==a){t.length=Math.max(t.length,a+1);u.length=Math.max(u.length,a+1);u[0]=0;var e=t[0]=0;for(c=a=0;c=C.length&&e()}var c=Cb(C,a);C[c]=b}}}function t(){var a=Q.viewport,b=Q.scissor_box;a[0]=a[1]=b[0]=b[1]=0;G.viewportWidth=G.framebufferWidth=G.drawingBufferWidth=a[2]=b[2]=l.drawingBufferWidth;G.viewportHeight=G.framebufferHeight=G.drawingBufferHeight=a[3]=b[3]=l.drawingBufferHeight}function w(){G.tick+=1;G.time=v();t();R.procs.poll()}function k(){y.refresh();t();R.procs.refresh();z&&z.update()}function v(){return(Db()- +E)/1E3}a=Ib(a);if(!a)return null;var l=a.gl,h=l.getContextAttributes();l.isContextLost();var g=Jb(l,a);if(!g)return null;var q=Fb(),r={vaoCount:0,bufferCount:0,elementsCount:0,framebufferCount:0,shaderCount:0,textureCount:0,cubeCount:0,renderbufferCount:0,maxTextureUnits:0},m=g.extensions,z=$b(l,m),E=Db(),F=l.drawingBufferWidth,K=l.drawingBufferHeight,G={tick:0,time:0,viewportWidth:F,viewportHeight:K,framebufferWidth:F,framebufferHeight:K,drawingBufferWidth:F,drawingBufferHeight:K,pixelRatio:a.pixelRatio}, +H=Yb(l,m),O=Kb(l,r,a,function(a){return J.destroyBuffer(a)}),J=Sb(l,m,H,r,O),M=Lb(l,m,O,r),D=Tb(l,q,r,a),y=Ob(l,m,H,function(){R.procs.poll()},G,r,a),L=Zb(l,m,H,r,a),V=Rb(l,m,H,y,L,r),R=Wb(l,q,m,H,O,M,y,V,{},J,D,{elements:null,primitive:4,count:-1,offset:0,instances:-1},G,z,a),q=Ub(l,V,R.procs.poll,G,h,m,H),Q=R.next,N=l.canvas,C=[],S=[],T=[],U=[a.onDestroy],aa=null;N&&(N.addEventListener("webglcontextlost",f,!1),N.addEventListener("webglcontextrestored",d,!1));var X=V.setFBO=p({framebuffer:Y.define.call(null, +1,"framebuffer")});k();h=A(p,{clear:function(a){if("framebuffer"in a)if(a.framebuffer&&"framebufferCube"===a.framebuffer_reglType)for(var b=0;6>b;++b)X(A({framebuffer:a.framebuffer.faces[b]},a),n);else X(a,n);else n(null,a)},prop:Y.define.bind(null,1),context:Y.define.bind(null,2),"this":Y.define.bind(null,3),draw:p({}),buffer:function(a){return O.create(a,34962,!1,!1)},elements:function(a){return M.create(a,!1)},texture:y.create2D,cube:y.createCube,renderbuffer:L.create,framebuffer:V.create,framebufferCube:V.createCube, +vao:J.createVAO,attributes:h,frame:u,on:function(a,b){var c;switch(a){case "frame":return u(b);case "lost":c=S;break;case "restore":c=T;break;case "destroy":c=U}c.push(b);return{cancel:function(){for(var a=0;a 0 && existing.length > m) { - existing.warned = true; - var w = new Error('Possible EventEmitter memory leak detected. ' + - existing.length + ' "' + String(type) + '" listeners ' + - 'added. Use emitter.setMaxListeners() to ' + - 'increase limit.'); - w.name = 'MaxListenersExceededWarning'; - w.emitter = target; - w.type = type; - w.count = existing.length; - if (typeof console === 'object' && console.warn) { - console.warn('%s: %s', w.name, w.message); - } - } - } - } +},{}],125:[function(require,module,exports){ +'use strict' - return target; -} +/** + * Remove a range of items from an array + * + * @function removeItems + * @param {Array<*>} arr The target array + * @param {number} startIdx The index to begin removing from (inclusive) + * @param {number} removeCount How many items to remove + */ +module.exports = function removeItems (arr, startIdx, removeCount) { + var i, length = arr.length -EventEmitter.prototype.addListener = function addListener(type, listener) { - return _addListener(this, type, listener, false); -}; + if (startIdx >= length || removeCount === 0) { + return + } -EventEmitter.prototype.on = EventEmitter.prototype.addListener; + removeCount = (startIdx + removeCount > length ? length - startIdx : removeCount) -EventEmitter.prototype.prependListener = - function prependListener(type, listener) { - return _addListener(this, type, listener, true); - }; + var len = length - removeCount -function onceWrapper() { - if (!this.fired) { - this.target.removeListener(this.type, this.wrapFn); - this.fired = true; - switch (arguments.length) { - case 0: - return this.listener.call(this.target); - case 1: - return this.listener.call(this.target, arguments[0]); - case 2: - return this.listener.call(this.target, arguments[0], arguments[1]); - case 3: - return this.listener.call(this.target, arguments[0], arguments[1], - arguments[2]); - default: - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) - args[i] = arguments[i]; - this.listener.apply(this.target, args); - } + for (i = startIdx; i < len; ++i) { + arr[i] = arr[i + removeCount] } -} -function _onceWrap(target, type, listener) { - var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; - var wrapped = bind.call(onceWrapper, state); - wrapped.listener = listener; - state.wrapFn = wrapped; - return wrapped; + arr.length = len } -EventEmitter.prototype.once = function once(type, listener) { - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); - this.on(type, _onceWrap(this, type, listener)); - return this; -}; - -EventEmitter.prototype.prependOnceListener = - function prependOnceListener(type, listener) { - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); - this.prependListener(type, _onceWrap(this, type, listener)); - return this; - }; +},{}],126:[function(require,module,exports){ +(function (global){(function (){ +module.exports = + global.performance && + global.performance.now ? function now() { + return performance.now() + } : Date.now || function now() { + return +new Date + } -// Emits a 'removeListener' event if and only if the listener was removed. -EventEmitter.prototype.removeListener = - function removeListener(type, listener) { - var list, events, position, i, originalListener; +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],127:[function(require,module,exports){ +module.exports = scrollToAnchor - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); +function scrollToAnchor (anchor, options) { + if (anchor) { + try { + var el = document.querySelector(anchor) + if (el) el.scrollIntoView(options) + } catch (e) {} + } +} - events = this._events; - if (!events) - return this; +},{}],128:[function(require,module,exports){ +var fastSafeStringify = require('fast-safe-stringify') +var copy = require('clipboard-copy') - list = events[type]; - if (!list) - return this; +function tryStringify (obj) { + try { + return JSON.stringify(obj) + } catch (e) {} +} - if (list === listener || list.listener === listener) { - if (--this._eventsCount === 0) - this._events = objectCreate(null); - else { - delete events[type]; - if (events.removeListener) - this.emit('removeListener', type, list.listener || listener); - } - } else if (typeof list !== 'function') { - position = -1; +function stateCopy (obj) { + var str = tryStringify(obj) || fastSafeStringify(obj) + copy(str) +} - for (i = list.length - 1; i >= 0; i--) { - if (list[i] === listener || list[i].listener === listener) { - originalListener = list[i].listener; - position = i; - break; - } - } +module.exports = stateCopy - if (position < 0) - return this; +},{"clipboard-copy":60,"fast-safe-stringify":63}],129:[function(require,module,exports){ +var C = "\u037c" +var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C) +var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : Symbol("styleSet") +var top = typeof globalThis != "undefined" ? globalThis : typeof window != "undefined" ? window : {} - if (position === 0) - list.shift(); - else - spliceOne(list, position); +// :: - Style modules encapsulate a set of CSS rules defined from +// JavaScript. Their definitions are only available in a given DOM +// root after it has been _mounted_ there with `StyleModule.mount`. +// +// Style modules should be created once and stored somewhere, as +// opposed to re-creating them every time you need them. The amount of +// CSS rules generated for a given DOM root is bounded by the amount +// of style modules that were used. So to avoid leaking rules, don't +// create these dynamically, but treat them as one-time allocations. +var StyleModule = exports.StyleModule = function StyleModule(spec, options) { + this.rules = [] + var ref = options || {}; + var finish = ref.finish; - if (list.length === 1) - events[type] = list[0]; + function splitSelector(selector) { + return /^@/.test(selector) ? [selector] : selector.split(/,\s*/) + } - if (events.removeListener) - this.emit('removeListener', type, originalListener || listener); + function render(selectors, spec, target, isKeyframes) { + var local = [], isAt = /^@(\w+)\b/.exec(selectors[0]), keyframes = isAt && isAt[1] == "keyframes" + if (isAt && spec == null) { return target.push(selectors[0] + ";") } + for (var prop in spec) { + var value = spec[prop] + if (/&/.test(prop)) { + render(prop.split(/,\s*/).map(function (part) { return selectors.map(function (sel) { return part.replace(/&/, sel); }); }).reduce(function (a, b) { return a.concat(b); }), + value, target) + } else if (value && typeof value == "object") { + if (!isAt) { throw new RangeError("The value of a property (" + prop + ") should be a primitive value.") } + render(splitSelector(prop), value, local, keyframes) + } else if (value != null) { + local.push(prop.replace(/_.*/, "").replace(/[A-Z]/g, function (l) { return "-" + l.toLowerCase(); }) + ": " + value + ";") } + } + if (local.length || keyframes) { + target.push((finish && !isAt && !isKeyframes ? selectors.map(finish) : selectors).join(", ") + + " {" + local.join(" ") + "}") + } + } - return this; - }; - -EventEmitter.prototype.removeAllListeners = - function removeAllListeners(type) { - var listeners, events, i; - - events = this._events; - if (!events) - return this; + for (var prop in spec) { render(splitSelector(prop), spec[prop], this.rules) } +}; - // not listening for removeListener, no need to emit - if (!events.removeListener) { - if (arguments.length === 0) { - this._events = objectCreate(null); - this._eventsCount = 0; - } else if (events[type]) { - if (--this._eventsCount === 0) - this._events = objectCreate(null); - else - delete events[type]; - } - return this; - } +// :: () → string +// Returns a string containing the module's CSS rules. +StyleModule.prototype.getRules = function getRules () { return this.rules.join("\n") }; - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - var keys = objectKeys(events); - var key; - for (i = 0; i < keys.length; ++i) { - key = keys[i]; - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = objectCreate(null); - this._eventsCount = 0; - return this; - } +// :: () → string +// Generate a new unique CSS class name. +StyleModule.newName = function newName () { + var id = top[COUNT] || 1 + top[COUNT] = id + 1 + return C + id.toString(36) +}; - listeners = events[type]; +// :: (union, union<[StyleModule], StyleModule>) +// +// Mount the given set of modules in the given DOM root, which ensures +// that the CSS rules defined by the module are available in that +// context. +// +// Rules are only added to the document once per root. +// +// Rule order will follow the order of the modules, so that rules from +// modules later in the array take precedence of those from earlier +// modules. If you call this function multiple times for the same root +// in a way that changes the order of already mounted modules, the old +// order will be changed. +StyleModule.mount = function mount (root, modules) { + (root[SET] || new StyleSet(root)).mount(Array.isArray(modules) ? modules : [modules]) +}; - if (typeof listeners === 'function') { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - for (i = listeners.length - 1; i >= 0; i--) { - this.removeListener(type, listeners[i]); - } - } +var adoptedSet = null - return this; - }; +var StyleSet = function StyleSet(root) { + if (!root.head && root.adoptedStyleSheets && typeof CSSStyleSheet != "undefined") { + if (adoptedSet) { + root.adoptedStyleSheets = [adoptedSet.sheet].concat(root.adoptedStyleSheets) + return root[SET] = adoptedSet + } + this.sheet = new CSSStyleSheet + root.adoptedStyleSheets = [this.sheet].concat(root.adoptedStyleSheets) + adoptedSet = this + } else { + this.styleTag = (root.ownerDocument || root).createElement("style") + var target = root.head || root + target.insertBefore(this.styleTag, target.firstChild) + } + this.modules = [] + root[SET] = this +}; -function _listeners(target, type, unwrap) { - var events = target._events; +StyleSet.prototype.mount = function mount (modules) { + var sheet = this.sheet + var pos = 0 /* Current rule offset */, j = 0 /* Index into this.modules */ + for (var i = 0; i < modules.length; i++) { + var mod = modules[i], index = this.modules.indexOf(mod) + if (index < j && index > -1) { // Ordering conflict + this.modules.splice(index, 1) + j-- + index = -1 + } + if (index == -1) { + this.modules.splice(j++, 0, mod) + if (sheet) { for (var k = 0; k < mod.rules.length; k++) + { sheet.insertRule(mod.rules[k], pos++) } } + } else { + while (j < index) { pos += this.modules[j++].rules.length } + pos += mod.rules.length + j++ + } + } - if (!events) - return []; + if (!sheet) { + var text = "" + for (var i$1 = 0; i$1 < this.modules.length; i$1++) + { text += this.modules[i$1].getRules() + "\n" } + this.styleTag.textContent = text + } +}; - var evlistener = events[type]; - if (!evlistener) - return []; +// Style::Object> +// +// A style is an object that, in the simple case, maps CSS property +// names to strings holding their values, as in `{color: "red", +// fontWeight: "bold"}`. The property names can be given in +// camel-case—the library will insert a dash before capital letters +// when converting them to CSS. +// +// If you include an underscore in a property name, it and everything +// after it will be removed from the output, which can be useful when +// providing a property multiple times, for browser compatibility +// reasons. +// +// A property in a style object can also be a sub-selector, which +// extends the current context to add a pseudo-selector or a child +// selector. Such a property should contain a `&` character, which +// will be replaced by the current selector. For example `{"&:before": +// {content: '"hi"'}}`. Sub-selectors and regular properties can +// freely be mixed in a given object. Any property containing a `&` is +// assumed to be a sub-selector. +// +// Finally, a property can specify an @-block to be wrapped around the +// styles defined inside the object that's the property's value. For +// example to create a media query you can do `{"@media screen and +// (min-width: 400px)": {...}}`. - if (typeof evlistener === 'function') - return unwrap ? [evlistener.listener || evlistener] : [evlistener]; - return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); -} +},{}],130:[function(require,module,exports){ +'use strict'; -EventEmitter.prototype.listeners = function listeners(type) { - return _listeners(this, type, true); -}; +Object.defineProperty(exports, '__esModule', { value: true }); -EventEmitter.prototype.rawListeners = function rawListeners(type) { - return _listeners(this, type, false); +var base = { + 8: "Backspace", + 9: "Tab", + 10: "Enter", + 12: "NumLock", + 13: "Enter", + 16: "Shift", + 17: "Control", + 18: "Alt", + 20: "CapsLock", + 27: "Escape", + 32: " ", + 33: "PageUp", + 34: "PageDown", + 35: "End", + 36: "Home", + 37: "ArrowLeft", + 38: "ArrowUp", + 39: "ArrowRight", + 40: "ArrowDown", + 44: "PrintScreen", + 45: "Insert", + 46: "Delete", + 59: ";", + 61: "=", + 91: "Meta", + 92: "Meta", + 106: "*", + 107: "+", + 108: ",", + 109: "-", + 110: ".", + 111: "/", + 144: "NumLock", + 145: "ScrollLock", + 160: "Shift", + 161: "Shift", + 162: "Control", + 163: "Control", + 164: "Alt", + 165: "Alt", + 173: "-", + 186: ";", + 187: "=", + 188: ",", + 189: "-", + 190: ".", + 191: "/", + 192: "`", + 219: "[", + 220: "\\", + 221: "]", + 222: "'", + 229: "q" }; -EventEmitter.listenerCount = function(emitter, type) { - if (typeof emitter.listenerCount === 'function') { - return emitter.listenerCount(type); - } else { - return listenerCount.call(emitter, type); - } +var shift = { + 48: ")", + 49: "!", + 50: "@", + 51: "#", + 52: "$", + 53: "%", + 54: "^", + 55: "&", + 56: "*", + 57: "(", + 59: ":", + 61: "+", + 173: "_", + 186: ":", + 187: "+", + 188: "<", + 189: "_", + 190: ">", + 191: "?", + 192: "~", + 219: "{", + 220: "|", + 221: "}", + 222: "\"", + 229: "Q" }; -EventEmitter.prototype.listenerCount = listenerCount; -function listenerCount(type) { - var events = this._events; +var chrome = typeof navigator != "undefined" && /Chrome\/(\d+)/.exec(navigator.userAgent); +var safari = typeof navigator != "undefined" && /Apple Computer/.test(navigator.vendor); +var gecko = typeof navigator != "undefined" && /Gecko\/\d+/.test(navigator.userAgent); +var mac = typeof navigator != "undefined" && /Mac/.test(navigator.platform); +var ie = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); +var brokenModifierNames = chrome && (mac || +chrome[1] < 57) || gecko && mac; - if (events) { - var evlistener = events[type]; +// Fill in the digit keys +for (var i = 0; i < 10; i++) base[48 + i] = base[96 + i] = String(i); - if (typeof evlistener === 'function') { - return 1; - } else if (evlistener) { - return evlistener.length; - } - } +// The function keys +for (var i = 1; i <= 24; i++) base[i + 111] = "F" + i; - return 0; +// And the alphabetic keys +for (var i = 65; i <= 90; i++) { + base[i] = String.fromCharCode(i + 32); + shift[i] = String.fromCharCode(i); } -EventEmitter.prototype.eventNames = function eventNames() { - return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; -}; - -// About 1.5x faster than the two-arg version of Array#splice(). -function spliceOne(list, index) { - for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) - list[i] = list[k]; - list.pop(); -} +// For each code that doesn't have a shift-equivalent, copy the base name +for (var code in base) if (!shift.hasOwnProperty(code)) shift[code] = base[code]; -function arrayClone(arr, n) { - var copy = new Array(n); - for (var i = 0; i < n; ++i) - copy[i] = arr[i]; - return copy; +function keyName(event) { + // Don't trust event.key in Chrome when there are modifiers until + // they fix https://bugs.chromium.org/p/chromium/issues/detail?id=633838 + var ignoreKey = brokenModifierNames && (event.ctrlKey || event.altKey || event.metaKey) || + (safari || ie) && event.shiftKey && event.key && event.key.length == 1; + var name = (!ignoreKey && event.key) || + (event.shiftKey ? shift : base)[event.keyCode] || + event.key || "Unidentified"; + // Edge sometimes produces wrong names (Issue #3) + if (name == "Esc") name = "Escape"; + if (name == "Del") name = "Delete"; + // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/ + if (name == "Left") name = "ArrowLeft"; + if (name == "Up") name = "ArrowUp"; + if (name == "Right") name = "ArrowRight"; + if (name == "Down") name = "ArrowDown"; + return name } -function unwrapListeners(arr) { - var ret = new Array(arr.length); - for (var i = 0; i < ret.length; ++i) { - ret[i] = arr[i].listener || arr[i]; - } - return ret; -} +exports.base = base; +exports.keyName = keyName; +exports.shift = shift; -function objectCreatePolyfill(proto) { - var F = function() {}; - F.prototype = proto; - return new F; -} -function objectKeysPolyfill(obj) { - var keys = []; - for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) { - keys.push(k); - } - return k; -} -function functionBindPolyfill(context) { - var fn = this; - return function () { - return fn.apply(context, arguments); - }; -} +},{}],131:[function(require,module,exports){ +/* eslint-disable node/no-deprecated-api */ +var assert = require('assert') -},{}],133:[function(require,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = (nBytes * 8) - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] +module.exports = getAllRoutes - i += d +var transform = function (trie, previous) { + var prev = previous || '/' + var routes = {} + var nodes = trie.nodes + Object.keys(nodes).forEach(function (key) { + var path = (prev === '/' ? prev : prev + '/') + (key === '$$' ? ':' + trie.name : key) + var cb = nodes[key].cb + if (cb !== undefined) { + routes[path] = cb + } + if (Object.keys(nodes[key].nodes).length !== 0) { + var obj = transform(nodes[key], path) + Object.keys(obj).forEach(function (r) { + routes[r] = obj[r] + }) + } + }) + return routes +} - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} +// walk a wayfarer trie +// (obj, fn) -> null +function getAllRoutes (router) { + assert.equal(typeof router, 'function', 'wayfarer.getAllRoutes: router should be an function') - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + var trie = router._trie + assert.equal(typeof trie, 'object', 'wayfarer.getAllRoutes: trie should be an object') - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) + var tree = trie.trie + return transform(tree) } -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = (nBytes * 8) - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 +},{"assert":93}],132:[function(require,module,exports){ +/* eslint-disable node/no-deprecated-api */ +var assert = require('assert') +var trie = require('./trie') - value = Math.abs(value) +module.exports = Wayfarer - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } +// create a router +// str -> obj +function Wayfarer (dft) { + if (!(this instanceof Wayfarer)) return new Wayfarer(dft) - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = ((value * c) - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } + var _default = (dft || '').replace(/^\//, '') + var _trie = trie() - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + emit._trie = _trie + emit.on = on + emit.emit = emit + emit.match = match + emit._wayfarer = true - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + return emit - buffer[offset + i - d] |= s * 128 -} + // define a route + // (str, fn) -> obj + function on (route, cb) { + assert.equal(typeof route, 'string') + assert.equal(typeof cb, 'function') -},{}],134:[function(require,module,exports){ -/* -object-assign -(c) Sindre Sorhus -@license MIT -*/ + route = route || '/' -'use strict'; -/* eslint-disable no-unused-vars */ -var getOwnPropertySymbols = Object.getOwnPropertySymbols; -var hasOwnProperty = Object.prototype.hasOwnProperty; -var propIsEnumerable = Object.prototype.propertyIsEnumerable; + if (cb._wayfarer && cb._trie) { + _trie.mount(route, cb._trie.trie) + } else { + var node = _trie.create(route) + node.cb = cb + node.route = route + } -function toObject(val) { - if (val === null || val === undefined) { - throw new TypeError('Object.assign cannot be called with null or undefined'); - } + return emit + } - return Object(val); -} + // match and call a route + // (str, obj?) -> null + function emit (route) { + var matched = match(route) -function shouldUseNative() { - try { - if (!Object.assign) { - return false; - } + var args = new Array(arguments.length) + args[0] = matched.params + for (var i = 1; i < args.length; i++) { + args[i] = arguments[i] + } - // Detect buggy property enumeration order in older V8 versions. + return matched.cb.apply(matched.cb, args) + } - // https://bugs.chromium.org/p/v8/issues/detail?id=4118 - var test1 = new String('abc'); // eslint-disable-line no-new-wrappers - test1[5] = 'de'; - if (Object.getOwnPropertyNames(test1)[0] === '5') { - return false; - } + function match (route) { + assert.notEqual(route, undefined, "'route' must be defined") - // https://bugs.chromium.org/p/v8/issues/detail?id=3056 - var test2 = {}; - for (var i = 0; i < 10; i++) { - test2['_' + String.fromCharCode(i)] = i; - } - var order2 = Object.getOwnPropertyNames(test2).map(function (n) { - return test2[n]; - }); - if (order2.join('') !== '0123456789') { - return false; - } + var matched = _trie.match(route) + if (matched && matched.cb) return new Route(matched) - // https://bugs.chromium.org/p/v8/issues/detail?id=3056 - var test3 = {}; - 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { - test3[letter] = letter; - }); - if (Object.keys(Object.assign({}, test3)).join('') !== - 'abcdefghijklmnopqrst') { - return false; - } + var dft = _trie.match(_default) + if (dft && dft.cb) return new Route(dft) - return true; - } catch (err) { - // We don't expect any of the above to throw, but better to be safe. - return false; - } -} + throw new Error("route '" + route + "' did not match") + } -module.exports = shouldUseNative() ? Object.assign : function (target, source) { - var from; - var to = toObject(target); - var symbols; + function Route (matched) { + this.cb = matched.cb + this.route = matched.route + this.params = matched.params + } +} - for (var s = 1; s < arguments.length; s++) { - from = Object(arguments[s]); +},{"./trie":133,"assert":93}],133:[function(require,module,exports){ +/* eslint-disable node/no-deprecated-api */ +var assert = require('assert') - for (var key in from) { - if (hasOwnProperty.call(from, key)) { - to[key] = from[key]; - } - } +module.exports = Trie - if (getOwnPropertySymbols) { - symbols = getOwnPropertySymbols(from); - for (var i = 0; i < symbols.length; i++) { - if (propIsEnumerable.call(from, symbols[i])) { - to[symbols[i]] = from[symbols[i]]; - } - } - } - } +// create a new trie +// null -> obj +function Trie () { + if (!(this instanceof Trie)) return new Trie() + this.trie = { nodes: {} } +} - return to; -}; +// create a node on the trie at route +// and return a node +// str -> obj +Trie.prototype.create = function (route) { + assert.equal(typeof route, 'string', 'route should be a string') + // strip leading '/' and split routes + var routes = route.replace(/^\//, '').split('/') -},{}],135:[function(require,module,exports){ -// shim for using process in browser -var process = module.exports = {}; + function createNode (index, trie) { + var thisRoute = (has(routes, index) && routes[index]) + if (thisRoute === false) return trie -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. + var node = null + if (/^:|^\*/.test(thisRoute)) { + // if node is a name match, set name and append to ':' node + if (!has(trie.nodes, '$$')) { + node = { nodes: {} } + trie.nodes.$$ = node + } else { + node = trie.nodes.$$ + } -var cachedSetTimeout; -var cachedClearTimeout; + if (thisRoute[0] === '*') { + trie.wildcard = true + } -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } + trie.name = thisRoute.replace(/^:|^\*/, '') + } else if (!has(trie.nodes, thisRoute)) { + node = { nodes: {} } + trie.nodes[thisRoute] = node + } else { + node = trie.nodes[thisRoute] } + // we must recurse deeper + return createNode(index + 1, node) + } + return createNode(0, this.trie) } -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } +// match a route on the trie +// and return the node +// str -> obj +Trie.prototype.match = function (route) { + assert.equal(typeof route, 'string', 'route should be a string') + var routes = route.replace(/^\//, '').split('/') + var params = {} -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; + function search (index, trie) { + // either there's no match, or we're done searching + if (trie === undefined) return undefined + var thisRoute = routes[index] + if (thisRoute === undefined) return trie -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); + if (has(trie.nodes, thisRoute)) { + // match regular routes first + return search(index + 1, trie.nodes[thisRoute]) + } else if (trie.name) { + // match named routes + try { + params[trie.name] = decodeURIComponent(thisRoute) + } catch (e) { + return search(index, undefined) + } + return search(index + 1, trie.nodes.$$) + } else if (trie.wildcard) { + // match wildcards + try { + params.wildcard = decodeURIComponent(routes.slice(index).join('/')) + } catch (e) { + return search(index, undefined) + } + // return early, or else search may keep recursing through the wildcard + return trie.nodes.$$ } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); + // no matches found + return search(index + 1) } -} + } -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; + var node = search(0, this.trie) - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); + if (!node) return undefined + node = Object.assign({}, node) + node.params = params + return node } -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; +// mount a trie onto a node at route +// (str, obj) -> null +Trie.prototype.mount = function (route, trie) { + assert.equal(typeof route, 'string', 'route should be a string') + assert.equal(typeof trie, 'object', 'trie should be a object') -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; + var split = route.replace(/^\//, '').split('/') + var node = null + var key = null -function noop() {} + if (split.length === 1) { + key = split[0] + node = this.create(key) + } else { + var head = split.join('/') + key = split[0] + node = this.create(head) + } -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; + Object.assign(node.nodes, trie.nodes) + if (trie.name) node.name = trie.name -process.listeners = function (name) { return [] } + // delegate properties from '/' to the new node + // '/' cannot be reached once mounted + if (node.nodes['']) { + Object.keys(node.nodes['']).forEach(function (key) { + if (key === 'nodes') return + node[key] = node.nodes[''][key] + }) + Object.assign(node.nodes, node.nodes[''].nodes) + delete node.nodes[''].nodes + } +} -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; +function has (object, property) { + return Object.prototype.hasOwnProperty.call(object, property) +} -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; +},{"assert":93}],134:[function(require,module,exports){ +module.exports = [ + { + key: 'src', + // color: '#f33' + }, + { + key: 'coord', + // color: '#ff3' + }, + { + key: 'color', + // color: '#3f3' + }, + { + key: 'combine', + // color: '#3ff' + }, + { + key: 'combineCoord', + // color: '#33f' + }, + { + key: 'ext', + }, + { + key: 'settings', + }, + { + key: 'array', + }, + { + key: 'audio', + }, +] },{}]},{},[6]); diff --git a/examples.js b/examples.js index 796f8a3..8d83be8 100644 --- a/examples.js +++ b/examples.js @@ -6,6 +6,7 @@ module.exports = { code: `noise(10, 0.1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -15,6 +16,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) .out(o0)`, comments: { en: "noise interpolating between different scales and offsets", + es: "ruido (noise) cambiando entre varias escalas y offsets", ja: "noise の異なるスケールやオフセットを補間", } } @@ -27,6 +29,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `voronoi(5,0.3,0.3).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -34,6 +37,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `voronoi(25,2,10).color(1,1,0).brightness(0.15).out(o0)`, comments: { en: "fireflies", + es: "luciérnagas", ja: "蛍", } } @@ -45,6 +49,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc( [1,10,50,100,250,500].fast(2) ).out(o0)`, comments: { en: "frequency", + es: "frecuencia", ja: "周波数", } }, @@ -52,6 +57,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc( () => Math.sin(time/10) * 100 ).out(o0)`, comments: { en: "frequency 2", + es: "frecuencia 2", ja: "周波数 2", } }, @@ -59,6 +65,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc( 10, [-10,-1,-0.1,0,0.1,1,10], 0 ).out(o0)`, comments: { en: "sync", + es: "sincronización", ja: "シンク(同期)", } }, @@ -66,6 +73,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `osc(10,0.1, ({time}) => Math.sin(time/10) * 100 ).out(o0)`, comments: { en: "offset", + es: "offset", ja: "オフセット", } }, @@ -77,6 +85,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `shape(3,0.5,0.001).out(o0)`, comments: { en: "triangle", + es: "triángulo", ja: "三角形", } }, @@ -84,6 +93,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `shape(100,0.5,0.001).out(o0)`, comments: { en: "ellipse", + es: "elipse", ja: "楕円", } }, @@ -91,6 +101,7 @@ noise( () => Math.sin(time/10)*50 , () => Math.sin(time/2)/500 ) code: `shape(100,0.01,1).invert(()=>Math.sin(time)*2).out(o0)`, comments: { en: "inverting blurry circle", + es: "círculo difuminado que se invierte", ja: "反転するぼかした円", } }, @@ -106,6 +117,7 @@ shape(5,0.5,0.1).repeat(19,19) .out(o0)`, comments: { en: "a... rainbow ball?", + es: "una... ¿bola de arcoíris?", ja: "虹色のボール…?", } }, @@ -117,6 +129,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `gradient([1,2,4]).out(o0)`, comments: { en: "gradient sequence at speeds of 1, 2 & 4", + es: "secuencia de degradés con velocidades de 1, 2 y 4", ja: "グラデーションのスピードを 1, 2, 4 の順に変える", } }, @@ -124,6 +137,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `gradient(0).r().repeat(16,1).scrollX(0,0.1).out(o0)`, comments: { en: "saw oscillator", + es: "oscilador de cierra", ja: "のこぎり波", } }, @@ -136,6 +150,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `src(o0).modulate(noise(3),0.005).blend(shape(4),0.01).out(o0)`, comments: { en: "feedback", + es: "retroalimentación (feedback)", ja: "フィードバック", } }, @@ -147,6 +162,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `solid([1,0,0],[0,1,0],[0,0,1],1).out(o0)`, comments: { en: "cycling through red, green and blue", + es: "cambiando entre rojo, verde y azul", ja: "赤、緑、青を行き来する", } }, @@ -159,6 +175,7 @@ shape(5,0.5,0.1).repeat(19,19) code: `osc(50).rotate( () => time%360 ).out(o0)`, comments: { en: "constant rotation", + es: "rotación constante", ja: "一定速度で回転", } }, @@ -169,6 +186,7 @@ osc(10,1,1) .out(o0)`, comments: { en: "modulate rotation speed", + es: "modulando la velocidad de rotación", ja: "回転速度を変化させる", } }, @@ -181,6 +199,7 @@ osc(10,1,1) code: `shape().scale(1.5,1,1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -195,6 +214,7 @@ shape().scale(1.5,[0.25,0.5,0.75,1].fast(0.25),[3,2,1]) .out(o0)`, comments: { en: "flower", + es: "flor", ja: "花", } }, @@ -207,6 +227,7 @@ shape().scale(1.5,[0.25,0.5,0.75,1].fast(0.25),[3,2,1]) code: `noise().pixelate(20,20).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -214,6 +235,7 @@ shape().scale(1.5,[0.25,0.5,0.75,1].fast(0.25),[3,2,1]) code: `noise().pixelate(2000,1).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -228,6 +250,7 @@ noise() .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -239,6 +262,7 @@ noise() code: `gradient(0).posterize( [1, 5, 15, 30] , 0.5 ).out(o0)`, comments: { en: "static gradient posterized, varying bins", + es: "gradiente estático, con una posterización cuya cantidad de tonos varía en el tiempo", ja: "", } }, @@ -246,6 +270,7 @@ noise() code: `gradient(0).posterize( 3, [0.1, 0.5, 1.0, 2.0] ).out(o0)`, comments: { en: "static gradient posterized, varying gamma", + es: "gradiente estático, con una posterización cuyo gamma varía en el tiempo", ja: "", } }, @@ -257,6 +282,7 @@ osc().posterize(3,1) .out(o0)`, comments: { en: "posterize (top); compare with pixelate (bottom)", + es: "posteriación (arriba); comparar con la pixelización (abajo)", ja: "", } }, @@ -268,6 +294,7 @@ osc().posterize(3,1) code: `osc().shift(0.1,0.9,0.3).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -279,6 +306,7 @@ osc().posterize(3,1) code: `shape().repeat(3.0, 3.0, 0.0, 0.0).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -291,6 +319,7 @@ shape(1.25,0.5,0.25) .out(o0)`, comments: { en: "dogtooth factory", + es: "pata de gallo", ja: "", } }, @@ -307,6 +336,7 @@ shape(4,0.9) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -318,6 +348,7 @@ shape(4,0.9) code: `shape().repeatX(3.0, 0.0).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -329,6 +360,7 @@ osc(5,0,1) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -346,6 +378,7 @@ shape(4,0.9) .out(o0)`, comments: { en: "straight lines illusion", + es: "ilusión de líneas rectas", ja: "", } }, @@ -357,6 +390,7 @@ shape(4,0.9) code: `shape().repeatY(3.0, 0.0).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -367,6 +401,7 @@ osc(5,0,1) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -384,6 +419,7 @@ shape(4,0.9) .out(o0)`, comments: { en: "morphing grid", + es: "cuadrícula cambiante", ja: "", } }, @@ -396,6 +432,7 @@ shape(4,0.9) code: `osc(25,-0.1,0.5).kaleid(50).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -403,6 +440,7 @@ shape(4,0.9) code: `osc(25,-0.1,0.5).kaleid(4).kaleid(4).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -421,6 +459,7 @@ osc(9,-0.1,0.1) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -430,6 +469,7 @@ osc(9,-0.1,0.1) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -441,6 +481,7 @@ osc(9,-0.1,0.1) code: `shape(3).scroll(0.1,-0.3).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -452,6 +493,7 @@ osc(9,-0.1,0.1) code: `osc(10,0,1).scrollX(0.5,0).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -459,6 +501,7 @@ osc(9,-0.1,0.1) code: `osc(10,0,1).scrollX([0,0.25,0.5,0.75,1].fast(4),0).out(o0)`, comments: { en: "x position", + es: "posición x (horizontal)", ja: "", } }, @@ -466,6 +509,7 @@ osc(9,-0.1,0.1) code: `gradient(1).scrollX(0, () => Math.sin(time*0.05)*0.05 ).out(o0)`, comments: { en: "scroll speed", + es: "velocidad de desplazamiento (scroll)", ja: "", } }, @@ -479,6 +523,7 @@ osc(9,-0.1,0.1) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -494,6 +539,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -504,6 +550,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "different scroll and speed", + es: "distinto desplazamiento y velocidad", ja: "", } }, @@ -515,6 +562,7 @@ voronoi(25,0,0) code: `osc(10,0,1).scrollY(0.5,0).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -522,6 +570,7 @@ voronoi(25,0,0) code: `osc(10,0,1).scrollY([0,0.25,0.5,0.75,1].fast(4),0).out(o0)`, comments: { en: "y position", + es: "posición y (vertical)", ja: "", } }, @@ -529,6 +578,7 @@ voronoi(25,0,0) code: `gradient(1).scrollY(0, ({time}) => Math.sin(time*0.05)*0.05 ).out()`, comments: { en: "scroll speed", + es: "velocidad de desplazamiento (scroll)", ja: "", } }, @@ -557,6 +607,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -567,6 +618,7 @@ voronoi(25,0,0) .out(o0)`, comments: { en: "different scroll and speed", + es: "distinto desplazamiento y velocidad", ja: "", } }, @@ -579,6 +631,7 @@ voronoi(25,0,0) code: `shape().scale(0.5).add(shape(4),[0,0.25,0.5,0.75,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -586,6 +639,7 @@ voronoi(25,0,0) code: `osc(9,0.1,1).add(osc(13,0.5,5)).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -597,6 +651,7 @@ voronoi(25,0,0) code: `osc().sub(osc(6)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -604,6 +659,7 @@ voronoi(25,0,0) code: `osc(6,0,1.5).modulate(noise(3).sub(gradient()),1).out(o0)`, comments: { en: "color remapping", + es: "reasignación de colores", ja: "", } }, @@ -616,6 +672,7 @@ voronoi(25,0,0) code: `solid(1,0,0,1).layer(shape(4).color(0,1,0,()=>Math.sin(time*2))).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -623,6 +680,7 @@ voronoi(25,0,0) code: `osc(30).layer(osc(15).rotate(1).luma()).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -635,6 +693,7 @@ voronoi(25,0,0) code: `shape().scale(0.5).blend(shape(4),[0,0.25,0.5,0.75,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -642,6 +701,7 @@ voronoi(25,0,0) code: `osc(9,0.1,1).blend(osc(13,0.5,5)).out()`, comments: { en: "", + es: "", ja: "", } }, @@ -649,6 +709,7 @@ voronoi(25,0,0) code: `osc().thresh().blend(o0,0.9).out(o0)`, comments: { en: "motion-blur like feedback", + es: "feedback con apariencia difuminada", ja: "", } }, @@ -661,6 +722,7 @@ voronoi(25,0,0) code: `osc(9,0.1,2).mult(osc(13,0.5,5)).out()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -671,6 +733,7 @@ osc() .out(o0)`, comments: { en: "mult is *not* transparent; compare with mask", + es: "mult *no* es transparente; compárese con mask", ja: "", } }, @@ -683,6 +746,7 @@ osc() code: `osc(9,0.1,1).diff(osc(13,0.5,5)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -696,6 +760,7 @@ osc(1,1,2) .out()`, comments: { en: "", + es: "", ja: "", } }, @@ -717,6 +782,7 @@ voronoi() .out(o0)`, comments: { en: "chocolate whirlpool", + es: "remolino de chocolate", ja: "", } }, @@ -727,6 +793,7 @@ osc(3,0,2) .out(o0)`, comments: { en: "color remapping", + es: "reasignación de colores", ja: "", } }, @@ -742,6 +809,7 @@ gradient(5).repeat(50,50).kaleid([3,5,7,9].fast(0.5)) .out(o0)`, comments: { en: "cosmic radiation", + es: "radiación cósmica", ja: "", } }, @@ -749,6 +817,7 @@ gradient(5).repeat(50,50).kaleid([3,5,7,9].fast(0.5)) code: `shape(4).modulateScale(gradient().g(),2,0.5).out(o0)`, comments: { en: "perspective", + es: "perspectiva", ja: "", } }, @@ -764,6 +833,7 @@ voronoi(10,1,5).brightness(()=>Math.random()*0.15) .out(o0)`, comments: { en: "what lies beneath", + es: "lo que se encuentra por debajo", ja: "", } }, @@ -773,6 +843,7 @@ noise(3).modulatePixelate(noise(3).pixelate(8,8),1024,8) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -789,6 +860,7 @@ voronoi(100,3,5) .out(o0)`, comments: { en: "wormhole", + es: "agujero de gusano", ja: "", } }, @@ -796,6 +868,7 @@ voronoi(100,3,5) code: `osc().modulateRotate(shape(999,0.3,0.5),1.57).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -812,6 +885,7 @@ src(o0) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -824,6 +898,7 @@ src(o0) code: `solid(1,1,1).invert([0,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -834,6 +909,7 @@ osc(4,0.1,2).invert().luma().invert() .mask(shape(2,0.5).scrollY(-0.25))).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -846,6 +922,7 @@ osc(4,0.1,2).invert().luma().invert() code: `osc(20).contrast( () => Math.sin(time) * 5 ).out(o0)`, comments: { en: "20Hz oscillator with contrast interpolating between 0.0-5.0", + es: "oscilador a 20Hz con un contraste que cambia entre 0.0-5.0", ja: "", } }, @@ -860,6 +937,7 @@ osc(20,0,2) .out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -867,6 +945,7 @@ osc(20,0,2) code: `noise().brightness(1).color(0.5,0.5,0.5).out(o0)`, comments: { en: "scaling noise value to 0-1", + es: "escalando el valor de noise a un rango de 0-1", ja: "", } }, @@ -878,6 +957,7 @@ osc(20,0,2) code: `gradient(5).mask(voronoi(),3,0.5).invert([0,1]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -888,6 +968,7 @@ osc() .out(o0)`, comments: { en: "mask is transparent; compare with mult", + es: "mask es transparente; compárese con mult", ja: "", } }, @@ -901,6 +982,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) .out(o0)`, comments: { en: "algae pulse", + es: "pulso de algas", ja: "", } }, @@ -912,6 +994,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `osc(10,0,1).luma(0.5,0.1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -919,6 +1002,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `osc(10,0,[0,0.5,1,2]).luma([0.1,0.25,0.75,1].fast(0.25),0.1).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -926,6 +1010,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `osc(30).layer(osc(15).rotate(1).luma()).out(o0)`, comments: { en: "luma is transparent; compare with thresh", + es: "luma es transparente; compárese con thresh", ja: "", } }, @@ -937,6 +1022,7 @@ osc(10,-0.25,1).color(0,0,1).saturate(2).kaleid(50) code: `noise(3,0.1).thresh(0.5,0.04).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -947,6 +1033,7 @@ noise(3,0.1) .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -954,6 +1041,7 @@ noise(3,0.1) code: `osc(30).layer(osc(15).rotate(1).thresh()).out(o0)`, comments: { en: "thresh is *not* transparent; compare with luma", + es: "thresh *no* es transparente; compárese con luma", ja: "", } }, @@ -965,6 +1053,7 @@ noise(3,0.1) code: `osc().color(1,0,3).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -976,6 +1065,7 @@ noise(3,0.1) code: `osc(10,0,1).saturate( () => Math.sin(time) * 10 ).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -987,6 +1077,7 @@ noise(3,0.1) code: `osc(30,0.1,1).hue(() => Math.sin(time)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1007,6 +1098,11 @@ osc(20) // color sequence of Red, Green, Blue, White, Black // colorama sequence of 0.005, 0.5, 1.0 at 1/8 speed // output to buffer o0`, + es: ` +// oscilador de 20Hz +// secuencia de color que cambia entre rojo, verde, azul, blanco y negro +// secuencia de colorama de 0.005, 0.5, 1.0 a un octavo de velocidad +// salida al buffer o0`, ja: "デフォルト", } }, @@ -1014,6 +1110,7 @@ osc(20) code: `osc(30,0.1,1).colorama(-0.1).out(o0)`, comments: { en: "negative value is less harsh", + es: "los valores negativos son más suaves", ja: "", } }, @@ -1025,6 +1122,7 @@ osc(20) code: `osc(60,0.1,1.5).layer(gradient().r()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1036,6 +1134,7 @@ osc(20) code: `osc(60,0.1,1.5).layer(gradient().g()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1047,6 +1146,7 @@ osc(20) code: `osc(60,0.1,1.5).layer(gradient().colorama(1).b()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1060,6 +1160,7 @@ s0.initCam() src(s0).invert().out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1073,6 +1174,7 @@ s0.initImage("https://upload.wikimedia.org/wikipedia/commons/2/25/Hydra-Foto.jpg osc(6).modulate(src(s0),1).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1086,6 +1188,7 @@ s0.initVideo("https://media.giphy.com/media/AS9LIFttYzkc0/giphy.mp4") src(s0).modulate(noise(3)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1105,6 +1208,7 @@ s0.init({src:canvas}) src(s0).modulate(osc().kaleid(999)).out(o0)`, comments: { en: "load canvas", + es: "cargar canvas", ja: "canvas をロード", } }, @@ -1118,6 +1222,7 @@ s0.initScreen() src(s0).colorama(0.5).out(o0)`, comments: { en: "select a window", + es: "selecciona una ventana", ja: "画面を選択", } }, @@ -1134,6 +1239,7 @@ gradient().out(o3) render()`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1143,6 +1249,7 @@ voronoi().out(o1) render(o1)`, comments: { en: "specify display buffer", + es: "especifica salida a renderizar", ja: "", } }, @@ -1157,6 +1264,7 @@ update = () => b += 0.01 * Math.sin(time) shape().scrollX(()=>b).out(o0)`, comments: { en: "update is called every frame", + es: "update es llamada cada fotograma", ja: "", } }, @@ -1170,6 +1278,7 @@ setResolution(100,100) osc().out(o0)`, comments: { en: "make the canvas small (100 pixel x 100 pixel)", + es: "hace al canvas muy pequeño (100 pixeles x 100 pixeles)", ja: "", } }, @@ -1183,6 +1292,7 @@ osc().out(o0) hush()`, comments: { en: "clear the buffers", + es: "limpia los buffers", ja: "", } }, @@ -1208,6 +1318,7 @@ setFunction({ osc(60,0.1,1.5).chroma().out(o0)`, comments: { en: "from https://www.shadertoy.com/view/XsfGzn", + es: "sacado de https://www.shadertoy.com/view/XsfGzn", ja: "", } }, @@ -1221,6 +1332,7 @@ speed = 3 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change overall speed", + es: "cambia la velocidad global", ja: "", } }, @@ -1230,6 +1342,7 @@ speed = 0.1 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change overall speed", + es: "cambia la velocidad global", ja: "", } }, @@ -1243,6 +1356,7 @@ bpm = 60 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change array speed", + es: "cambia la velocidad de los arrays", ja: "", } }, @@ -1252,6 +1366,7 @@ bpm = 15 osc(60,0.1,[0,1.5]).out(o0)`, comments: { en: "change array speed", + es: "cambia la velocidad de los arrays", ja: "", } }, @@ -1264,6 +1379,7 @@ osc(60,0.1,[0,1.5]).out(o0)`, shape(99).scrollX(() => -mouse.x / width).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1276,6 +1392,7 @@ shape(99).scrollX(() => -mouse.x / width).out(o0)`, shape(99).scrollY(() => -mouse.y / height).out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1287,6 +1404,7 @@ shape(99).scrollY(() => -mouse.y / height).out(o0)`, code: `shape(2,0.8).kaleid(()=>6+Math.sin(time)*4).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1302,6 +1420,7 @@ shape(99).scroll( .out(o0)`, comments: { en: "", + es: "", ja: "", } }, @@ -1313,6 +1432,7 @@ shape(99).scroll( code: `osc([10,30,60].fast(2),0.1,1.5).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1320,6 +1440,7 @@ shape(99).scroll( code: `osc([10,30,60].fast(0.5),0.1,1.5).out(o0)`, comments: { en: "argument less than 1 makes transition slower", + es: "un argumento menor a 1 hace a las transiciones más lentas", ja: "", } }, @@ -1331,6 +1452,7 @@ shape(99).scroll( code: `shape(999).scrollX([-0.2,0.2].smooth()).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1342,6 +1464,7 @@ shape(99).scroll( code: `shape(4).rotate([-3.14,3.14].ease('easeInOutCubic')).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1357,6 +1480,7 @@ shape(999).scrollY(.2).scrollX([-0.2,0.2]) ).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1368,6 +1492,7 @@ shape(999).scrollY(.2).scrollX([-0.2,0.2]) code: `shape().scrollX([0,1,2,3,4].fit(-0.2,0.2)).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1379,6 +1504,7 @@ shape(999).scrollY(.2).scrollX([-0.2,0.2]) code: `osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1392,6 +1518,7 @@ a.setSmooth(0.8) osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "default", + es: "default", ja: "デフォルト", } }, @@ -1405,6 +1532,7 @@ a.setCutoff(4) osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "threshold", + es: "umbral (threshold)", ja: "", } }, @@ -1418,6 +1546,7 @@ a.setBins(8) osc(60,0.1,()=>a.fft[7]*3).modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "change color with hissing noise", + es: "cambiando el color con ruido", ja: "", } }, @@ -1431,6 +1560,7 @@ a.setScale(5) osc().modulate(noise(3),()=>a.fft[0]).out(o0)`, comments: { en: "the smaller the scale is, the bigger the output is", + es: "cuanto menor la escala, mayor es la salida", ja: "", } }, diff --git a/index.js b/index.js index 65055cc..b4e64d9 100644 --- a/index.js +++ b/index.js @@ -203,7 +203,7 @@ function mainView (state, emit) {
emit('clear details') }> ${i18next.t('title')}
- ${state.page.selected === null ? '' : `::: ${state.page.selected.name}`} + ${state.page.selected === null ? '' : ` ::: ${state.page.selected.name}`}
${ languageView(state, emit) }
diff --git a/locales.js b/locales.js index fa49225..5afa9a6 100644 --- a/locales.js +++ b/locales.js @@ -24,6 +24,30 @@ module.exports = { 'openin': 'open in editor', } }, + es: { + translation: { + 'language-name': 'Spanish', + 'example': 'Ejemplo', + 'usage': 'Uso', + 'title': 'Funciones de hydra', + 'intro': `Hay 5 tipos de funciones en hydra: señales generadoras (sources), de geometría, de color, de fusón, y de modulación. + Haz click en cualquier función aquí abajo para ver su uso. (Para una documentación más detallada, puedes ver la página web de hydra, + primeros pasos o el Hydra Book.)`, + 'editor-info': 'Edita el código y presiona el botón "▶" o usa "ctrl+enter" para ejecutarlo!', + 'src': 'Source', + 'coord': 'Geometría', + 'color': 'Color', + 'combine': 'Fusión', + 'combineCoord': 'Modulación', + 'ext': 'Fuentes externas', + 'settings': 'Ajustes del sintetizador', + 'array': 'Array', + 'audio': 'Audio', + 'run': 'ejecutar', + 'reset': 'reset', + 'openin': 'abrir en el editor', + } + }, ja: { translation: { 'language-name': '日本語',