2 // This file contains most of the magic that extracts "context
3 // information" from the unstructered layout-oriented stuff in an
7 #include "math_charinset.h"
8 #include "math_deliminset.h"
9 #include "math_exfuncinset.h"
10 #include "math_funcinset.h"
11 #include "math_matrixinset.h"
12 #include "math_mathmlstream.h"
13 #include "math_scriptinset.h"
14 #include "math_stringinset.h"
15 #include "math_symbolinset.h"
19 std::ostream & operator<<(std::ostream & os, MathArray const & ar)
27 MathScriptInset const * asScript(MathArray::const_iterator it)
29 if (it->nucleus()->asScriptInset())
34 return it->nucleus()->asScriptInset();
39 // returns sequence of char with same code starting at it up to end
40 // it might be less, though...
41 string charSequence(MathArray::const_iterator it, MathArray::const_iterator end)
44 MathCharInset const * p = it->nucleus()->asCharInset();
46 for (MathTextCodes c = p->code(); it != end; ++it) {
47 p = it->nucleus()->asCharInset();
48 if (!p || p->code() != c)
57 void extractStrings(MathArray & dat)
59 //lyxerr << "\nStrings from: " << ar << "\n";
61 MathArray::const_iterator it = dat.begin();
62 while (it != dat.end()) {
63 if (it->nucleus() && it->nucleus()->asCharInset()) {
64 string s = charSequence(it, dat.end());
65 MathTextCodes c = it->nucleus()->asCharInset()->code();
66 ar.push_back(MathAtom(new MathStringInset(s, c)));
74 //lyxerr << "\nStrings to: " << ar << "\n";
78 MathInset * singleItem(MathArray & ar)
80 return ar.size() == 1 ? ar.begin()->nucleus() : 0;
84 void extractMatrices(MathArray & ar)
86 lyxerr << "\nMatrices from: " << ar << "\n";
87 for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) {
88 MathDelimInset * del = (*it)->asDelimInset();
91 MathInset * arr = singleItem(del->cell(0));
92 if (!arr || !arr->asArrayInset())
94 *it = MathAtom(new MathMatrixInset(*(arr->asArrayInset())));
95 lyxerr << "\nMatrices to: " << ar << "\n";
99 // convert this inset somehow to a string
100 string extractString(MathInset * p)
102 if (p && p->getChar())
103 return string(1, p->getChar());
104 if (p && p->asStringInset())
105 return p->asStringInset()->str();
110 // define a function for tests
111 typedef bool TestItemFunc(MathInset *);
113 // define a function for replacing pa
114 typedef MathInset * ReplaceArgumentFunc(const MathArray & ar);
116 // search end of nested sequence
117 MathArray::iterator searchNestedEnd(
118 MathArray::iterator it,
119 MathArray::iterator last,
120 TestItemFunc testOpen,
121 TestItemFunc testClose
124 for (int level = 0; it != last; ++it) {
125 if (testOpen(it->nucleus()))
127 if (testClose(it->nucleus()))
136 // replace nested sequences by a real Insets
139 TestItemFunc testOpen,
140 TestItemFunc testClose,
141 ReplaceArgumentFunc replaceArg
144 // use indices rather than iterators for the loop because we are going
145 // to modify the array.
146 for (MathArray::size_type i = 0; i < ar.size(); ++i) {
147 // check whether this is the begin of the sequence
148 MathArray::iterator it = ar.begin() + i;
149 if (!testOpen(it->nucleus()))
152 // search end of sequence
153 MathArray::iterator jt = searchNestedEnd(it, ar.end(), testOpen, testClose);
157 // create a proper inset as replacement
158 MathInset * p = replaceArg(MathArray(it + 1, jt));
160 // replace the original stuff by the new inset
161 ar.erase(it + 1, jt + 1);
167 bool testParanOpen(MathInset * p)
169 return extractString(p) == "(";
173 bool testParanClose(MathInset * p)
175 return extractString(p) == ")";
179 MathInset * replaceByDelimInset(const MathArray & ar)
181 MathDelimInset * del = new MathDelimInset("(", ")");
187 // replace '('...')' sequences by a real MathDelimInset
188 void extractDelims(MathArray & ar) {
189 lyxerr << "\nDelims from: " << ar << "\n";
190 replaceNested(ar, testParanOpen, testParanClose, replaceByDelimInset);
191 lyxerr << "\nDelims to: " << ar << "\n";
195 // replace 'f' '(...)' and 'f' '^n' '(...)' sequences by a real MathExFuncInset
196 // assume 'extractDelims' ran before
197 void extractFunctions(MathArray & ar)
199 // we need at least two items...
203 lyxerr << "\nFunctions from: " << ar << "\n";
204 for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
205 MathArray::iterator it = ar.begin() + i;
207 // is this a function name?
208 MathFuncInset * func = (*it)->asFuncInset();
212 // do we have an exponent?
213 // simply skippping the postion does the right thing:
214 // 'sin' '^2' 'x' -> 'sin(x)' '^2'
215 MathArray::iterator jt = it + 1;
216 if (MathScriptInset * script = (*jt)->asScriptInset()) {
217 // allow superscripts only
218 if (script->hasDown())
225 // jt points now to the "argument". Since we had run "extractDelims"
226 // before, this could be a single argument only. Get hold of this.
228 MathDelimInset * del = (*jt)->asDelimInset();
229 if (del && del->isParanthesis())
234 // replace the function name by a real function inset
235 (*it).reset(new MathExFuncInset(func->name(), arg));
237 // remove the source of the argument from the array
239 lyxerr << "\nFunctions to: " << ar << "\n";
244 bool testIntSymbol(MathInset * p)
246 return p->asSymbolInset() && p->asSymbolInset()->name() == "int";
250 bool testSmallD(MathInset * p)
252 string s = extractString(p);
253 return s.size() && s[0] == 'd';
257 // replace '\int' ['_^'] x 'd''x'(...)' sequences by a real MathExIntInset
258 // assume 'extractDelims' ran before
259 void extractIntegrals(MathArray & ar)
261 // we need at least three items...
265 lyxerr << "\nIntegrals from: " << ar << "\n";
266 for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
267 MathArray::iterator it = ar.begin() + i;
269 // is this a integral name?
270 if (!testIntSymbol(it->nucleus()))
274 MathArray::iterator jt =
275 searchNestedEnd(it, ar.end(), testIntSymbol, testSmallD);
277 // create a proper inset as replacement
278 //MathInset * p = replaceArg(MathArray(it + 1, jt));
280 // replace the original stuff by the new inset
281 //ar.erase(it + 1, jt + 1);
287 void extractStructure(MathArray & ar)
292 extractFunctions(ar);
293 extractIntegrals(ar);
297 void write(MathArray const & dat, WriteStream & wi)
301 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
302 MathInset const * p = it->nucleus();
303 if (it + 1 != ar.end()) {
304 if (MathScriptInset const * q = asScript(it)) {
315 void normalize(MathArray const & ar, NormalStream & os)
317 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
318 (*it)->normalize(os);
322 void octavize(MathArray const & dat, OctaveStream & os)
325 extractStructure(ar);
326 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
327 MathInset const * p = it->nucleus();
328 if (it + 1 != ar.end()) {
329 if (MathScriptInset const * q = asScript(it)) {
340 void maplize(MathArray const & dat, MapleStream & os)
343 extractStructure(ar);
344 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
345 MathInset const * p = it->nucleus();
346 if (it + 1 != ar.end()) {
347 if (MathScriptInset const * q = asScript(it)) {
358 void mathmlize(MathArray const & dat, MathMLStream & os)
361 extractStructure(ar);
364 else if (ar.size() == 1)
365 os << ar.begin()->nucleus();
368 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
369 MathInset const * p = it->nucleus();
370 if (it + 1 != ar.end()) {
371 if (MathScriptInset const * q = asScript(it)) {