Commit d1c4a96a authored by Michael Murtaugh's avatar Michael Murtaugh

stylerun.js

parent 881c9ace
node_modules/
package-lock.json
venv/
var etherpad = (function (exports) {
'use strict';
// Z:9kj>1|8=al=o4*1a|1+1$
async function wait (time) {
return new Promise(resolve => {
setTimeout(resolve, time);
})
}
// e.g. Z:9kj>1|8=al=o4*1a|1+1$
function changeset_parse (c) {
let changeset_pat = /^Z:([0-9a-z]+)([><])([0-9a-z]+)(.+?)\$/,
op_pat = /(\|([0-9a-z]+)([\+\-\=])([0-9a-z]+))|([\*\+\-\=])([0-9a-z]+)/g,
......@@ -48,12 +53,6 @@ var etherpad = (function (exports) {
return ret;
}
async function wait (time) {
return new Promise(resolve => {
setTimeout(resolve, time);
})
}
class Etherpad {
static async load (filename, padname) {
......@@ -62,6 +61,7 @@ var etherpad = (function (exports) {
data = await resp.json(),
pad_data = data[`pad:${padname}`];
var pad = new Etherpad(padname);
pad.json = data;
pad.parse_json(data);
return pad;
}
......@@ -76,6 +76,7 @@ var etherpad = (function (exports) {
var curtext = "\n";
for (var i=0; i<=this.last_rev; i++) {
let change = this.perform_changeset_curline(curtext, this.changesets[i]);
change.rev = i;
callback(change);
curtext = change.text;
// console.log(curtext);
......@@ -88,6 +89,7 @@ var etherpad = (function (exports) {
let pad_data = data[`pad:${this.padname}`],
last_rev = pad_data.head;
// parse the changesets / revisions
this.changesets = [];
this.last_rev = last_rev;
// console.log("loaded");
......@@ -104,6 +106,10 @@ var etherpad = (function (exports) {
return last_rev;
}
get_attrib (n) {
return this.json.pool.numToAttrib[""+n];
}
perform_changeset (input_text, c) {
let textpos = 0,
bank = c.bank,
......
......@@ -4,7 +4,7 @@ import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
export default [{
input: 'src/app.js',
input: 'src/etherpad.js',
output: {
file: 'dist/etherpad.js',
format: 'iife',
......
// Z:9kj>1|8=al=o4*1a|1+1$
async function wait (time) {
return new Promise(resolve => {
setTimeout(resolve, time);
})
}
// e.g. Z:9kj>1|8=al=o4*1a|1+1$
function changeset_parse (c) {
let changeset_pat = /^Z:([0-9a-z]+)([><])([0-9a-z]+)(.+?)\$/,
op_pat = /(\|([0-9a-z]+)([\+\-\=])([0-9a-z]+))|([\*\+\-\=])([0-9a-z]+)/g,
......@@ -45,10 +51,117 @@ function changeset_parse (c) {
return ret;
}
async function wait (time) {
return new Promise(resolve => {
setTimeout(resolve, time);
})
class Attributes {
constructor (attr) {
this.attributes = attr || [];
// an attribute entry has the form
// {
// start: set,
// end: set
// }
}
insert (startpos, endpos, attributes) {
// scan over the affected characters
// read current attributes at startpos
// extend / add as needed
// arrange state per attribute index...
// each attribute index is either on or off at any given position...
// Maintain "style runs" for each attribute as
// ordered lists of pairs of starting and ending (character) indexes
// load current state at startpos... advance each "style run" to a certain character position
var attrs = set();
for (let i=0; i<startpos; i++) {
let d = this.attributes[i];
if (d) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
let ee = d.end.entries(),
e = ee.next();
while (!e.done) {
attrs.delete(e.value[1]);
e = ee.next();
}
ee = d.start.entries();
e = ee.next();
while (!e.done) {
attrs.add(e.value[1]);
e = ee.next();
}
}
}
// assert
for (let i=0; i<numchars; i++) {
let p = pos+i,
attr = this.attributes[p];
if (attr === undefined) {
this.attributes[p] = attr = new Set();
}
attributes.forEach(x => { attr.add(x) });
}
}
delete (pos, numchars) {
this.attributes.splice(pos, numchars);
}
copy () {
return new Attributes(this.attributes.slice());
}
get_runs (startpos, endpos) {
}
}
class Text {
constructor (text, attr) {
this.text = text;
this.attributes = attr;
if (attr == undefined) {
this.attributes = new Attributes();
}
}
perform_changeset (c) {
// process the given change set returning a new Text object
let textpos = 0,
textline = 0,
bank = c.bank,
bankpos = 0,
newtext = '',
current_attributes = [];
// loop through the operations
// rebuilding the final text
for (let i=0, ops=c.ops.length; i<ops; i++) {
let op = c.ops[i];
if (op.op != "attr") {
// console.log(op);
// record this attribute at current
// add op to current attibutes to be applied to subsequent inserts
current_attributes.push(op.index);
// attributes.set(textpos, op.index)
}
if (op.op == "insert") {
let newtextposition = newtext.length,
insertion_text = bank.substring(bankpos, bankpos+op.chars);
newtext += insertion_text;
// advance positions
bankpos += op.chars;
this.attributes.insert(newtextposition, op.chars, current_attributes);
// importantly, on an insert, the (original/old/previous) textpos
// does *not* increment...
} else if (op.op == "delete") {
// todo: delete attributes as well
this.attributes.delete(textpos, op.chars);
textpos += op.chars;
} else if (op.op == "hold") {
newtext += this.text.substring(textpos, textpos+op.chars);
textpos += op.chars;
}
}
// append rest of old text...
newtext += this.text.substring(textpos);
return new Text(newtext, this.attributes.slice());
}
}
export class Etherpad {
......@@ -59,6 +172,7 @@ export class Etherpad {
data = await resp.json(),
pad_data = data[`pad:${padname}`];
var pad = new Etherpad(padname);
pad.json = data;
pad.parse_json(data);
return pad;
}
......@@ -73,6 +187,7 @@ export class Etherpad {
var curtext = "\n";
for (var i=0; i<=this.last_rev; i++) {
let change = this.perform_changeset_curline(curtext, this.changesets[i]);
change.rev = i;
callback(change);
curtext = change.text;
// console.log(curtext);
......@@ -85,6 +200,7 @@ export class Etherpad {
let pad_data = data[`pad:${this.padname}`],
last_rev = pad_data.head;
// parse the changesets / revisions
this.changesets = [];
this.last_rev = last_rev;
// console.log("loaded");
......@@ -101,6 +217,10 @@ export class Etherpad {
return last_rev;
}
get_attrib (n) {
return this.json.pool.numToAttrib[""+n];
}
perform_changeset (input_text, c) {
let textpos = 0,
textline = 0,
......
class StyleRun {
constructor () {
this.runs = [];
}
add (start, end) {
let i=0,
len = this.runs.length,
run;
for (; i<len; i++) {
run = this.runs[i];
if (run.start > end) {
// incoming interval is fully before
// insert incoming interval before i
this.runs.splice(i, 0, {start: start, end: end});
return;
}
if (start < run.end) {
// eventually extend start (left) -- "union"
run.start = Math.min(start, run.start);
// new interval intersects i
if (end <= run.end) {
// new interval is contained within i... do nothing
return;
}
// merge any subsequent overlapping intervals
let j=i+1,
delcount = 0;
while (j<len && this.runs[j].start <= end) {
// eventually extend end -- "union"
end = Math.max(end, this.runs[j].end);
delcount += 1;
j += 1;
}
this.runs.splice(i+1, delcount);
run.end = end;
return;
}
}
// append new interval
this.runs.push({start: start, end: end});
}
insert (start, chars) {
let i=0,
len = this.runs.length,
run;
for (; i<len; i++) {
run = this.runs[i];
if (start < run.start) {
// insertion point is fully before
// insert new interval
this.runs.splice(i, 0, {start: start, end: start+chars});
// shift subsequent intervals
for (let j=i+1; j<len; j++) {
this.runs[j].start += chars;
this.runs[j].end += chars;
}
return;
} else if (start <= run.end) {
// insertion point intersects this interval, nb start may === run.end
// extend this interval
run.end += chars;
// and shift all subsequent...
for (let j=i+1; j<len; j++) {
this.runs[j].start += chars;
this.runs[j].end += chars;
}
return;
}
}
// add new interval clean at the end
this.runs.push({start: start, end: start+chars});
}
delete (start, chars) {
let end = start + chars,
i=0,
len = this.runs.length,
run;
for (; i<len; i++) {
// console.log(`RUN${i}`)
run = this.runs[i];
if (end <= run.start) {
// console.log("CLEANBEFORE");
// console.log("shifting all subsequent intervals")
// cleanly before
// shift all subsequent intervals -chars
for (let j=i; j<len; j++) {
this.runs[j].start -= chars;
this.runs[j].end -= chars;
}
return;
}
// end >= run.start
if (start < run.end) {
// console.log("INTERSECTION");
// new interval intersects i
// nb: start might actually be before run.start
if (start <= run.start) {
if (end >= run.end) {
// deletion area completely overlaps interval
this.runs.splice(i, 1);
len -= 1;
i -= 1;
} else {
// deletion area overlaps start of interval
run.start = start;
run.end -= chars;
}
} else if (end <= run.end) {
// deletion is within interval
run.end -= chars;
} else {
// delection area overlaps end of interval
run.end = start;
}
} else {
// CLEAN AFTER
// nothing more to do
break;
}
}
}
unparse () {
var ret = '';
for (let i=0, len=this.runs.length; i<len; i++) {
ret += `(${this.runs[i].start}, ${this.runs[i].end})\n`;
}
return ret;
}
}
// var sr = new StyleRun();
// sr.insert(10, 10);
// console.log("---");
// console.log(sr.unparse());
// var pos = 1,
// del = 18;
// sr.delete(pos, del);
// console.log("---");
// console.log(`delete(${pos},${del})`)
// console.log("---");
// console.log(sr.unparse());
// should join
//sr.insert(10, 10);
//sr.insert(20, 10);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment