Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to get exact caret position if multiple array matrix are present. #2546

Open
devraj112 opened this issue Nov 7, 2024 · 6 comments
Open

Comments

@devraj112
Copy link

Issue

Not getting the exact caret position using mf.position.

Steps that are specific and repeatable

  1. This is the value in the input box which contains two matrix saparated by a \sqrt equation.
<script src="https://unpkg.com/mathlive"></script>
<script src="//unpkg.com/@cortex-js/compute-engine"></script>

<math-field>
  \begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}\sqrt{asdfasdfsdfsdf}\begin{array}{cc}d & x+y\\ p-q & 4\end{array}
</math-field>
  1. My cursor at "4^" in the second matrix \begin{array}{cc}d & x+y\\ p-q & 4\end{array}.

  2. With this code if you see the output. It is very confusing.

let mf = document.querySelector("math-field")

mf.addEventListener('selection-change', () => {
     console.log(mf.position, "position") //45 "position"
});

console.log("latex extended", mf.getValue("latex-extented"))  //  \begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}\sqrt{asdfasdfsdfsdf}\begin{array}{cc}d & x+y\\ p-q & 4\end{array}
"
console.log(mf.getValue(0, 45, "latex")) // "\begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}\sqrt{asdfasdfsdfsdf}dx+yp-q4"

console.log(mf.value.substring(0, 113)) " //  \begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}\sqrt{asdfasdfsdfsdf}\begin{array}{cc}d & x+y\\ p-q & 4"

In this console.log(mf.getValue(0, 45, "latex")) what happened to second matrix array? dx+yp-q4 why this output?

Expected Behavior

I think the mf.position should return 113. If not how can I get the whole second array matrix i.e. \begin{array}{cc}d & x+y\\ p-q & 4\end{array}

Code pen

https://codepen.io/devraj112/pen/LYwgJOO

if this link does not work:

<script src="//unpkg.com/@cortex-js/compute-engine"></script>
<math-field>
  \begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}\sqrt{asdfasdfsdfsdf}\begin{array}{cc}d & x+y\\ p-q & 4\end{array}
</math-field>
let mf = document.querySelector("math-field")

mf.addEventListener('selection-change', () => {
     console.log(mf.position, "position")
});

console.log("latex extended", mf.getValue("latex-extented"))
console.log(mf.getValue(0, 45, "latex"))
console.log(mf.value.substring(0, 113))

###This is my first post here, Sorry, If I missed following any guidelines.

@arnog
Copy link
Owner

arnog commented Nov 7, 2024

Thanks for following the issue template! This is a good report.

I think this is behaving correctly, but the meaning of position might be confusing. The position property refers to the places where the cursor can be positioned: the first position, at the very beginning of the expression is position 0, and the last one, after the last matrix, is position 46.

This is a position in a tree that represents the expression. It does not correspond to an index in the LaTeX string representing this expression. The same expression can be represented in ASCII Math, and the string representation would be different, and have different indexes.

The first matrix is from position 0 to position 17.

@arnog arnog added the not a bug label Nov 7, 2024
@devraj112
Copy link
Author

Thank you for the response.

So, how can I get the exact position of the cursor in the latex string?

With a regex I am able to extract the matrix from the whole equation. After that I am trying to find where the cursor is, as in this case(d & x+y\\ p-q & 4^) the second matrix but when I am using the 45(mf.position) value and checking for that in the mf.getValue("latex-extended") then obviously position 45 is inside the first matrix(\begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array})

    const mf = this.mathfield.nativeElement as MathfieldElement;
    const cursorPosition = mf.position;

    const fullLatex = mf.getValue('latex-expanded');
    const matrices = [...fullLatex.matchAll(/\\begin\{array\}(.*?)\\end\{array\}/g)];
    /*
      [
        "\begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}", 
       "{lc}a+1 & b+1\\ c & \frac{1}{d}"
      ],
      [
        "\begin{array}{cc}d & x+y\\ p-q & 4\end{array}", 
        "{cc}d & x+y\\ p-q & 4"
       ]
    */

    const activeMatrix = matrices.find((matrix) => {
        const start = matrix.index as number;
        const end = start + matrix[0].length;
        return cursorPosition >= start && cursorPosition <= end;
    });

With 45 as position value I am not even able to reach to the 2nd matrix.

So, What other option do I have here instead of mf.position? how to get the exact offset value?

@arnog
Copy link
Owner

arnog commented Nov 7, 2024

Yes, that is as expected. Again, the "position" and "index in a LaTeX string" are completely unrelated values. Just like "position" and "index in an ASCIIMath string" or "position" and "horizontal coordinate on the screen of the cursor".

Could you explain what you are trying to do? That's not very clear from what you've described so far. If you're trying to get the LaTeX representation from the start of the expression to the current position, you can use mf.getValue([0, mf.position]).

If you're trying to "understand" the input in the mathfield, you can use mf.expression to get a representation of the expression as a MathJSON syntax tree, which is independent of the LaTeX representation.

@devraj112
Copy link
Author

Could you explain what you are trying to do?

My requirement is to align the matrix column based on user requirement("left", "right", "centre").

For instance, I have a angular popup like contextual balloon which will be taking input("left", "right", "centre") from the user for aligning the specific matrix column where the user has placed their cursor. After taking input I am just changing the format in the matrix array {lcr}.

So, for that I need the cursor position of the according to the full latex.

setAlignment(alignment: 'left' | 'center' | 'right'): void {
            const mf = this.mathfield.nativeElement as MathfieldElement;
    const cursorPosition = mf.position;

    const fullLatex = mf.getValue('latex-expanded');
    const matrices = [...fullLatex.matchAll(/\\begin\{array\}(.*?)\\end\{array\}/g)];
    /*
      [
        "\begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}", 
       "{lc}a+1 & b+1\\ c & \frac{1}{d}"
      ],
      [
        "\begin{array}{cc}d & x+y\\ p-q & 4\end{array}", 
        "{cc}d & x+y\\ p-q & 4"
       ]
    */

    const activeMatrix = matrices.find((matrix) => {
        const start = matrix.index as number;
        const end = start + matrix[0].length;
        return cursorPosition >= start && cursorPosition <= end;
    });
    
        if (activeMatrix) {
            const alignmentChar = alignment === 'left' ? 'l' : alignment === 'right' ? 'r' : 'c';
            const updatedLatex = this.updateMatrixAlignment(fullLatex, activeMatrix, cursorPosition, alignmentChar);
    
            mf.setValue(updatedLatex, { format: 'latex' });
        } else {
            console.warn('Cursor is not in a matrix');
        }
    }

Here, in the above method I am extracting the matrix from the equation. And iterating the matrices until I found the matrix where the user cursor is.

updateMatrixAlignment(matrixLatex: string, targetMatrix: string, cursorPosition: number, alignmentChar: string): string {
        const envRegex = /\\begin\{array\}\{([lcr]+)\}/;
        const match = targetMatrix.match(envRegex);
    
        if (match) {
            let alignments = match[1].split('');
            
            const colIndex = this.determineColumnFromCursor(targetMatrix, cursorPosition);
            if (colIndex >= 0 && colIndex < alignments.length) {
                alignments[colIndex] = alignmentChar;
                const updatedTargetMatrix = targetMatrix.replace(envRegex, `\\begin{array}{${alignments.join('')}}`);
                return matrixLatex.replace(targetMatrix, updatedTargetMatrix);
            }
        }
    
        return matrixLatex;
    }

Here, I am focusing on the target matrix and after that getting the column. And at the end updating the column alignment of the target matrix.

The walkaround:

If you're trying to get the LaTeX representation from the start of the expression to the current position, you can use mf.getValue([0, mf.position]).

Full latex: \begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}\sqrt{asdfasdfsdfsdf}\begin{array}{cc}d & x+y\\ p-q & 4\end{array}

output from mf.getValue([0, mf.position]): "\begin{array}{lc}a+1 & b+1\\ c & \frac{1}{d}\end{array}\sqrt{asdfasdfsdfsdf}dx+yp-q4"

Here, why the second matrix is not coming with the full latex?

If you're trying to "understand" the input in the mathfield, you can use mf.expression to get a representation of the expression as a MathJSON syntax tree, which is independent of the LaTeX representation.

I am trying to get the position based on the full latex.

@arnog
Copy link
Owner

arnog commented Nov 8, 2024

OK, thanks for the explanation. I now understand what you're trying to do.

Something important to understand is that the math-field is not a LaTeX editor. It's a math equation editor. Internally, the equation is represented as a tree. It is possible to convert LaTeX into that tree, and the tree into LaTeX or MathML or ASCIIMath. However, the editing state (position, etc...) are relative to the tree structure, not to the LaTeX, which is only generated on demand.

There is a mf.getElementInfo() method that provides information about the current selection or caret position, however it currently does not include the information that you need (i.e. that the caret is inside a matrix). This is something I've been considering, however so it may get added in a future version.

@devraj112
Copy link
Author

Thank you for the clarity.

I will try to find a walkaround. Thanks for the support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants