commit e743f6f6d3e57ae7e687e3e1adc964aadf23d3ee
Author: Enrico Forestieri <for...@lyx.org>
Date:   Sun May 18 22:14:43 2025 +0200

    Fix bug #13186
    
    Correctly parse \prod constructs for maxima, mathematica and maple.
---
 src/mathed/InsetMathExInt.cpp |  6 ++++
 src/mathed/MathExtern.cpp     | 84 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/src/mathed/InsetMathExInt.cpp b/src/mathed/InsetMathExInt.cpp
index 70d1ba1604..05a58d964b 100644
--- a/src/mathed/InsetMathExInt.cpp
+++ b/src/mathed/InsetMathExInt.cpp
@@ -75,6 +75,8 @@ void InsetMathExInt::maple(MapleStream & os) const
 {
        if (symbol_ == "int" || symbol_ == "intop")
                os << (os.maxima() ? "integrate(" : "int(");
+       else if (symbol_ == "prod")
+               os << "product(";
        else
                os << symbol_ << '(';
 
@@ -100,6 +102,8 @@ void InsetMathExInt::maxima(MaximaStream & os) const
 {
        if (symbol_ == "int" || symbol_ == "intop")
                os << "integrate(";
+       else if (symbol_ == "prod")
+               os << "product(";
        else
                os << symbol_ << '(';
 
@@ -119,6 +123,8 @@ void InsetMathExInt::mathematica(MathematicaStream & os) 
const
                os << "Integrate[";
        else if (symbol_ == "sum")
                os << "Sum[";
+       else if (symbol_ == "prod")
+               os << "Product[";
        else
                os << symbol_ << '[';
 
diff --git a/src/mathed/MathExtern.cpp b/src/mathed/MathExtern.cpp
index 43ae76f0af..7834331216 100644
--- a/src/mathed/MathExtern.cpp
+++ b/src/mathed/MathExtern.cpp
@@ -372,9 +372,10 @@ void splitScripts(MathData & md)
                        continue;
 
                if (script->nuc().size() == 1) {
-                       // leave alone sums and integrals
+                       // leave alone sums, prods and integrals
                        MathAtom const & atom = script->nuc().front();
-                       if (testSymbol(atom, "sum") || testSymbol(atom, "int"))
+                       if (testSymbol(atom, "sum") || testSymbol(atom, "int")
+                           || testSymbol(atom, "prod"))
                                continue;
                }
 
@@ -842,6 +843,81 @@ void extractSums(MathData & md)
 }
 
 
+//
+// search prods
+//
+
+
+bool testProdSymbol(MathAtom const & p)
+{
+       return testSymbol(p, from_ascii("prod"));
+}
+
+
+bool testProd(MathAtom const & at)
+{
+       return
+        testProdSymbol(at) ||
+               ( at->asScriptInset()
+                 && !at->asScriptInset()->nuc().empty()
+                       && testProdSymbol(at->asScriptInset()->nuc().back()) );
+}
+
+
+// replace '\prod' ['_^'] f(x) sequences by a real InsetMathExInt
+// assume 'extractDelims' ran before
+void extractProds(MathData & md)
+{
+       // we need at least two items...
+       if (md.size() < 2)
+               return;
+
+       Buffer * buf = md.buffer();
+
+       //lyxerr << "\nProds from: " << md << endl;
+       for (size_t i = 0; i + 1 < md.size(); ++i) {
+               MathData::iterator it = md.begin() + i;
+
+               // is this a prod name?
+               if (!testProd(md[i]))
+                       continue;
+
+               // create a proper inset as replacement
+               auto p = make_unique<InsetMathExInt>(buf, from_ascii("prod"));
+
+               // collect lower bound and summation index
+               InsetMathScript const * sub = md[i]->asScriptInset();
+               if (sub && sub->hasDown()) {
+                       // try to figure out the product index from the 
subscript
+                       MathData const & ar = sub->down();
+                       MathData::const_iterator xt =
+                               find_if(ar.begin(), ar.end(), &testEqualSign);
+                       if (xt != ar.end()) {
+                               // we found a '=', use everything in front of 
that as index,
+                               // and everything behind as lower index
+                               p->cell(1) = MathData(buf, ar.begin(), xt);
+                               p->cell(2) = MathData(buf, xt + 1, ar.end());
+                       } else {
+                               // use everything as product index, don't use 
scripts.
+                               p->cell(1) = ar;
+                       }
+               }
+
+               // collect upper bound
+               if (sub && sub->hasUp())
+                       p->cell(3) = sub->up();
+
+               // use something  behind the script as core
+               MathData::iterator tt = extractTerm(p->cell(0), it + 1, 
md.end());
+
+               // cleanup
+               md.erase(it + 1, tt);
+               *it = MathAtom(p.release());
+       }
+       //lyxerr << "\nProds to: " << md << endl;
+}
+
+
 //
 // search differential stuff
 //
@@ -1021,8 +1097,10 @@ void extractStructure(MathData & md, ExternalMath kind)
                splitScripts(md);
        extractDelims(md);
        extractIntegrals(md, kind);
-       if (kind != MATHML && kind != HTML)
+       if (kind != MATHML && kind != HTML) {
                extractSums(md);
+               extractProds(md);
+       }
        extractNumbers(md);
        extractMatrices(md);
        if (kind != MATHML && kind != HTML) {
-- 
lyx-cvs mailing list
lyx-cvs@lists.lyx.org
https://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to