Skip to content

Commit 57bb574

Browse files
very wip: try restoring selection / cursor from startIndex and endIndex
1 parent 66f7eea commit 57bb574

File tree

4 files changed

+219
-37
lines changed

4 files changed

+219
-37
lines changed

src/publicapi.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,50 @@ function getInterface(v: number): MathQuill.v3.API | MathQuill.v1.API {
346346
return this;
347347
}
348348

349-
return this.__controller.exportLatexSelection().selection;
349+
const out = this.__controller.exportLatexSelection();
350+
351+
// TODO - the point of the below code is to allow us to play with a mathquill live and verify
352+
// that while we move selection around we are computing the correct cursor / selection positions.
353+
// This will all go away when the actual logic gets nailed down.
354+
const uncleanedIndicies = mapFromCleanedToUncleanedIndices(
355+
out.selection.latex,
356+
out.ctx.latex,
357+
out.selection
358+
);
359+
360+
const cursor = this.__controller.cursor;
361+
if (cursor.selection) {
362+
console.log('REAL SELECTION[L]', cursor.selection.getEnd(L));
363+
console.log('REAL SELECTION[R]', cursor.selection.getEnd(R));
364+
} else {
365+
console.log('REAL CURSOR[PARENT]', cursor.parent);
366+
console.log('REAL CURSOR[L]', cursor[L]);
367+
console.log('REAL CURSOR[R]', cursor[R]);
368+
}
369+
console.log('---- simulate applying selection ---');
370+
const results = this.__controller.exportLatexSelection(uncleanedIndicies);
371+
console.log('=== done simulate applying selection ===');
372+
373+
if (cursor.selection) {
374+
if (
375+
cursor.selection.getEnd(L) !== results.ctx.restoreInfo?.selectionL ||
376+
cursor.selection.getEnd(R) !== results.ctx.restoreInfo?.selectionR
377+
) {
378+
// TODO -- I think maybe this is now never being hit. SelectionL and SelectionR might be solid.
379+
console.log('computed wrong selection');
380+
debugger;
381+
}
382+
} else {
383+
if (cursor.parent !== results.ctx.restoreInfo?.cursorParent) {
384+
// TODO -- computing the wrong parent when you put cursor inside of an empty () or empty sqrt(). I think
385+
// there's something about MathBlocks that are special.
386+
// TODO -- not even trying to get cursorL and cursorR correct yet.
387+
console.log('wrong cursor parent');
388+
debugger;
389+
}
390+
}
391+
392+
return out.selection;
350393
}
351394
html() {
352395
return this.__controller.root

src/services/latex.ts

Lines changed: 107 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,23 @@ class Controller_latex extends Controller_keystroke {
194194
const currentSelectionInfo = this.exportLatexSelection();
195195
const currentLatex = currentSelectionInfo.selection.latex;
196196
const newLatex = data.latex;
197-
const { cursorInsertPath, signedSelectionSize } = data.opaqueSnapshot;
198197

199-
// latex's must match for the indicies in the selection to match up
200-
if (currentLatex !== newLatex) return;
198+
// latexs must match for the startIndex and endIndex to match up
199+
if (newLatex !== currentLatex) return;
200+
201+
// the data.startIndex and data.endIndex are values that are relative to the
202+
// cleaned latex. The problem is that when we traverse this tree looking for
203+
// the nodes in those positions we will be working on raw uncleaned latex. We need
204+
// to map our cleaned indices back to uncleaned indices. Then we can take another
205+
// pass through the tree looking for the nodes at the startIndex and endIndex
206+
const mappedIndices = mapFromCleanedToUncleanedIndices(
207+
currentLatex,
208+
currentSelectionInfo.ctx.latex,
209+
data
210+
);
211+
this.exportLatexSelection(mappedIndices);
201212

202-
// TODO - track things better so that we can actually make this work
203-
if (currentLatex !== currentSelectionInfo.ctx.latex) {
204-
throw new Error(
205-
'TODO - restoring selection requires uncleanedLatex to match latex'
206-
);
207-
}
213+
const { cursorInsertPath, signedSelectionSize } = data.opaqueSnapshot;
208214

209215
if (!this.insertCursorAtPath(cursorInsertPath)) return;
210216

@@ -243,7 +249,10 @@ class Controller_latex extends Controller_keystroke {
243249
return count;
244250
}
245251

246-
exportLatexSelection(): {
252+
exportLatexSelection(restoreInfo?: {
253+
uncleanStartIndex: number;
254+
uncleanEndIndex: number;
255+
}): {
247256
selection: ExportedLatexSelection;
248257
ctx: LatexContext;
249258
} {
@@ -253,6 +262,13 @@ class Controller_latex extends Controller_keystroke {
253262
endIndex: -1
254263
};
255264

265+
if (restoreInfo) {
266+
ctx.restoreInfo = {
267+
startIndex: restoreInfo.uncleanStartIndex,
268+
endIndex: restoreInfo.uncleanEndIndex
269+
};
270+
}
271+
256272
let cursorInsertPath: string = '';
257273
let signedSelectionSize: number = 0;
258274

@@ -289,28 +305,11 @@ class Controller_latex extends Controller_keystroke {
289305
// need to clean the latex
290306
var uncleanedLatex = ctx.latex;
291307
var cleanLatex = this.cleanLatex(uncleanedLatex);
292-
var startIndex = ctx.startIndex;
293-
var endIndex = ctx.endIndex;
294-
295-
// assumes that the cleaning process will only remove characters. We
296-
// run through the uncleanedLatex and cleanLatex to find differences.
297-
// when we find differences we see how many characters are dropped until
298-
// we sync back up. While detecting missing characters we decrement the
299-
// startIndex and endIndex if appropriate.
300-
var j = 0;
301-
for (var i = 0; i < ctx.endIndex; i++) {
302-
if (uncleanedLatex[i] !== cleanLatex[j]) {
303-
if (i < ctx.startIndex) {
304-
startIndex -= 1;
305-
}
306-
endIndex -= 1;
307-
308-
// do not increment j. We wan to keep looking at this same
309-
// cleanLatex character until we find it in the uncleanedLatex
310-
} else {
311-
j += 1; //move to next cleanLatex character
312-
}
313-
}
308+
const { startIndex, endIndex } = mapFromUncleanedToCleanedIndices(
309+
uncleanedLatex,
310+
cleanLatex,
311+
ctx
312+
);
314313

315314
return {
316315
selection: {
@@ -596,3 +595,79 @@ class Controller_latex extends Controller_keystroke {
596595
}
597596
}
598597
}
598+
599+
function mapFromUncleanedToCleanedIndices(
600+
uncleanedLatex: string,
601+
cleanedLatex: string,
602+
indices: { startIndex: number; endIndex: number }
603+
) {
604+
var startIndex = indices.startIndex;
605+
var endIndex = indices.endIndex;
606+
607+
// assumes that the cleaning process will only remove space characters. We
608+
// run through the uncleanedLatex and cleanLatex to find differences.
609+
// when we find differences we see how many characters are dropped until
610+
// we sync back up. While detecting missing characters we decrement the
611+
// startIndex and endIndex if appropriate.
612+
for (
613+
var uncleanIdx = 0, cleanIdx = 0;
614+
uncleanIdx < indices.endIndex;
615+
uncleanIdx++
616+
) {
617+
if (uncleanedLatex[uncleanIdx] !== cleanedLatex[cleanIdx]) {
618+
if (uncleanIdx < indices.startIndex) {
619+
startIndex -= 1;
620+
}
621+
endIndex -= 1;
622+
623+
// do not increment j. We wan to keep looking at this same
624+
// cleanLatex character until we find it in the uncleanedLatex
625+
} else {
626+
cleanIdx += 1; //move to next cleanLatex character
627+
}
628+
}
629+
630+
return {
631+
startIndex,
632+
endIndex
633+
};
634+
}
635+
636+
function mapFromCleanedToUncleanedIndices(
637+
cleanedLatex: string,
638+
uncleanedLatex: string,
639+
indices: { startIndex: number; endIndex: number }
640+
) {
641+
const cleanStartIdx = indices.startIndex;
642+
const cleanEndIdx = indices.endIndex;
643+
var uncleanStartIndex = cleanStartIdx;
644+
var uncleanEndIndex = cleanEndIdx;
645+
646+
// assumes that the cleaning process will only remove space characters. We
647+
// run through the uncleanedLatex moving one character every time. We compare
648+
// against the cleanedLatex. If the cleanedLatex matches we consume a cleanedLatex
649+
// character. Otherwise we continue pointing to the same cleanedLatex character until
650+
// it matches the uncleanedLatex. When we find mismatches we know that we need to increase
651+
// the startIndex and endIndex to correspond to the correct uncleaned positions.
652+
for (
653+
var uncleanIdx = 0, cleanIdx = 0;
654+
uncleanIdx < uncleanedLatex.length;
655+
uncleanIdx++
656+
) {
657+
if (uncleanedLatex[uncleanIdx] !== cleanedLatex[cleanIdx]) {
658+
if (cleanIdx <= cleanStartIdx) {
659+
uncleanStartIndex += 1;
660+
}
661+
if (cleanIdx <= cleanEndIdx) {
662+
uncleanEndIndex += 1;
663+
}
664+
} else {
665+
cleanIdx += 1;
666+
}
667+
}
668+
669+
return {
670+
uncleanStartIndex,
671+
uncleanEndIndex
672+
};
673+
}

src/shared_types.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ type LatexContext = {
4545
startSelectionAfter?: NodeBase;
4646
endSelectionBefore?: NodeBase;
4747
endSelectionAfter?: NodeBase;
48+
restoreInfo?: {
49+
startIndex: number;
50+
endIndex: number;
51+
selectionL?: NodeBase;
52+
selectionR?: NodeBase;
53+
cursorL?: NodeBase;
54+
cursorParent?: NodeBase;
55+
};
4856
};
4957

5058
type ControllerData = any;

src/tree.ts

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,19 +345,75 @@ class NodeBase {
345345
}
346346
latexRecursive(_ctx: LatexContext): void {}
347347
checkCursorContextOpen(ctx: LatexContext) {
348+
const latexLength = ctx.latex.length;
348349
if (ctx.startSelectionBefore === this) {
349-
ctx.startIndex = ctx.latex.length;
350+
ctx.startIndex = latexLength;
350351
}
351352
if (ctx.endSelectionBefore === this) {
352-
ctx.endIndex = ctx.latex.length;
353+
ctx.endIndex = latexLength;
354+
}
355+
356+
const restoreInfo = ctx.restoreInfo;
357+
if (restoreInfo) {
358+
console.log(
359+
'open: ',
360+
[restoreInfo.startIndex, restoreInfo.endIndex],
361+
this,
362+
ctx.latex,
363+
latexLength
364+
);
365+
366+
if (latexLength === restoreInfo.startIndex) {
367+
if (restoreInfo.endIndex === restoreInfo.startIndex) {
368+
// caret
369+
if (latexLength === restoreInfo.startIndex) {
370+
//if (!restoreInfo.cursorParent) {
371+
restoreInfo.cursorParent = this.parent;
372+
console.log('Cursor parent =', this.parent);
373+
//}
374+
375+
console.log('Cursor start = ', this);
376+
}
377+
} else {
378+
// selection
379+
restoreInfo.selectionL = this;
380+
}
381+
}
353382
}
354383
}
355384
checkCursorContextClose(ctx: LatexContext) {
385+
const latexLength = ctx.latex.length;
386+
356387
if (ctx.startSelectionAfter === this) {
357-
ctx.startIndex = ctx.latex.length;
388+
ctx.startIndex = latexLength;
358389
}
359390
if (ctx.endSelectionAfter === this) {
360-
ctx.endIndex = ctx.latex.length;
391+
ctx.endIndex = latexLength;
392+
}
393+
394+
const restoreInfo = ctx.restoreInfo;
395+
if (restoreInfo) {
396+
console.log(
397+
'close: ',
398+
[restoreInfo.startIndex, restoreInfo.endIndex],
399+
this,
400+
ctx.latex,
401+
latexLength
402+
);
403+
404+
if (latexLength === restoreInfo.endIndex) {
405+
if (restoreInfo.startIndex === restoreInfo.endIndex) {
406+
// caret
407+
console.log('Cursor end = ', this);
408+
if (!restoreInfo.cursorParent) {
409+
console.log('Cursor parent =', this.parent);
410+
restoreInfo.cursorParent = this.parent;
411+
}
412+
} else {
413+
// selection
414+
restoreInfo.selectionR = this;
415+
}
416+
}
361417
}
362418
}
363419
finalizeTree(_options: CursorOptions, _dir?: Direction) {}

0 commit comments

Comments
 (0)