]> git.lyx.org Git - lyx.git/blob - src/mathed/math_extern.C
908c6f73eda54eb4a4bfbb21ad59f1044f7b85c3
[lyx.git] / src / mathed / math_extern.C
1
2 // This file contains most of the magic that extracts "context
3 // information" from the unstructered layout-oriented stuff in an
4 // MathArray.
5
6
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 "debug.h"
16
17
18 std::ostream & operator<<(std::ostream & os, MathArray const & ar)
19 {
20         NormalStream ns(os);    
21         ns << ar;
22         return os;
23 }
24
25
26 MathScriptInset const * asScript(MathArray::const_iterator it)
27 {
28         if (it->nucleus()->asScriptInset())
29                 return 0;
30         ++it;
31         if (!it->nucleus())
32                 return 0;
33         return it->nucleus()->asScriptInset();
34 }
35
36
37
38 // returns sequence of char with same code starting at it up to end
39 // it might be less, though...
40 string charSequence(MathArray::const_iterator it, MathArray::const_iterator end)
41 {
42         string s;
43         MathCharInset const * p = it->nucleus()->asCharInset();
44         if (p) {
45                 for (MathTextCodes c = p->code(); it != end; ++it) {
46                         if (!it->nucleus())
47                                 break;
48                         p = it->nucleus()->asCharInset();
49                         if (!p || p->code() != c)
50                                 break;
51                         s += p->getChar();
52                 }
53         }
54         return s;
55 }
56
57
58 void extractStrings(MathArray & dat)
59 {
60         //lyxerr << "\nStrings from: " << ar << "\n";
61         MathArray ar;
62         MathArray::const_iterator it = dat.begin();
63         while (it != dat.end()) {
64                 if (it->nucleus() && it->nucleus()->asCharInset()) {
65                         string s = charSequence(it, dat.end());
66                         MathTextCodes c = it->nucleus()->asCharInset()->code();
67                         ar.push_back(MathAtom(new MathStringInset(s, c)));
68                         it += s.size();
69                 } else {
70                         ar.push_back(*it);
71                         ++it;
72                 }
73         }
74         ar.swap(dat);
75         //lyxerr << "\nStrings to: " << ar << "\n";
76 }
77
78
79 bool needAsterisk(MathAtom const &, MathAtom const &)
80 {
81         return false;
82 }
83
84
85 void guessAsterisks(MathArray & dat)
86 {
87         if (dat.size() <= 1)
88                 return;
89         MathArray ar;
90         ar.push_back(*dat.begin());
91         MathArray::const_iterator it = dat.begin();
92         MathArray::const_iterator jt = it + 1;
93         for (; jt != dat.end(); ++it, ++jt) {
94                 if (needAsterisk(*it, *jt))
95                         ar.push_back(MathAtom(new MathCharInset('*')));
96                 ar.push_back(*it);
97         }
98         ar.push_back(*dat.end());
99         ar.swap(dat);
100 }
101
102
103 MathInset * singleItem(MathArray & ar)
104 {
105         lyxerr << "ar.size: " << ar.size() << "\n";
106         //lyxerr << "ar.begin: " << ar.begin() << "\n";
107         //lyxerr << "ar.nuc: " << ar.begin()->nucleus() << "\n";
108         lyxerr << "ar.nuc: " << *ar.begin()->nucleus() << "\n";
109         return ar.size() == 1 ? ar.begin()->nucleus() : 0;
110 }
111
112
113 void extractMatrices(MathArray & ar)
114 {
115         lyxerr << "\nMatrices from: " << ar << "\n";
116         for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) {
117                 if (!it->nucleus())
118                         continue;       
119                 MathDelimInset * del = it->nucleus()->asDelimInset();
120                 if (!del)
121                         continue;
122                 MathInset * arr = singleItem(del->cell(0));
123                 if (!arr || !arr->asArrayInset())
124                         continue;
125                 *it = MathAtom(new MathMatrixInset(*(arr->asArrayInset())));
126                 lyxerr << "\nMatrices to: " << ar << "\n";
127         }
128
129
130 // convert this inset somehow to a string
131 string extractString(MathInset * p)
132 {
133         if (p && p->getChar())
134                 return string(1, p->getChar());
135         if (p && p->asStringInset())
136                 return p->asStringInset()->str();
137         return string();
138 }
139
140
141 // replace '('...')' sequences by a real MathDelimInset
142 void extractDelims(MathArray & ar) {
143         // use indices rather than iterators for the loop  because we are going
144         // to modify the array.
145         lyxerr << "\nDelims from: " << ar << "\n";
146         for (MathArray::size_type i = 0; i < ar.size(); ++i) {
147                 MathArray::iterator it = ar.begin() + i;
148                 if (extractString(it->nucleus()) != "(")
149                         continue;
150
151                 // search matching closing paranthesis
152                 int level = 1;
153                 MathArray::iterator jt = it + 1;
154                 for (; jt != ar.end(); ++jt) {
155                         string s = extractString(jt->nucleus());
156                         if (s == "(")
157                                 ++level;
158                         if (s == ")")
159                                 --level;
160                         if (level == 0)
161                                 break;
162                 }
163                 if (jt == ar.end())
164                         continue;
165
166                 // create a proper deliminset
167                 MathAtom at(new MathDelimInset("(", ")"));
168                 at->cell(0) = MathArray(it + 1, jt);
169
170                 // replace the original stuff by the new inset
171                 ar.erase(it + 1, jt + 1);
172                 *it = at;
173                 lyxerr << "\nDelims to: " << ar << "\n";
174         }
175
176
177
178 // replace 'f' '(...)' and 'f' '^n' '(...)' sequences by a real MathExFuncInset
179 // assume 'extractDelims' ran before
180 void extractFunctions(MathArray & ar)
181 {
182         // we need at least two items...
183         if (ar.size() <= 1)
184                 return;
185
186         lyxerr << "\nFunctions from: " << ar << "\n";
187         for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
188                 MathArray::iterator it = ar.begin() + i;
189
190                 // is this a function name?
191                 if (!it->nucleus())
192                         continue;       
193                 MathFuncInset * func = (*it)->asFuncInset();
194                 if (!func)
195                         continue;
196
197                 // do we have an exponent?
198                 // simply skippping the postion does the right thing:
199                 // 'sin' '^2' 'x' -> 'sin(x)' '^2'
200                 MathArray::iterator jt = it + 1;
201                 if (MathScriptInset * script = (*jt)->asScriptInset()) {
202                         // allow superscripts only
203                         if (script->hasDown())
204                                 continue;
205                         ++jt;
206                         if (jt == ar.end())
207                                 continue;
208                 }
209
210                 // jt points now to the "argument". Since we had run "extractDelims"
211                 // before, this could be a single argument only. Get hold of this.
212                 MathArray arg;
213                 MathDelimInset * del = (*jt)->asDelimInset();
214                 if (del && del->isParanthesis()) 
215                         arg = del->cell(0);
216                 else
217                         arg.push_back(*jt);
218
219                 // replace the function name by a real function inset
220                 (*it).reset(new MathExFuncInset(func->name(), arg));
221                 
222                 // remove the source of the argument from the array
223                 ar.erase(jt);
224                 lyxerr << "\nFunctions to: " << ar << "\n";
225         }
226
227
228
229 void extractStructure(MathArray & ar)
230 {
231         extractStrings(ar);
232         extractMatrices(ar);
233         extractDelims(ar);
234         extractFunctions(ar);
235 }
236
237
238 void write(MathArray const & dat, WriteStream & wi)
239 {
240         MathArray ar = dat;
241         extractStrings(ar);
242         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
243                 MathInset const * p = it->nucleus();
244                 if (it + 1 != ar.end()) {
245                         if (MathScriptInset const * q = asScript(it)) {
246                                 q->write(p, wi);
247                                 ++it;
248                                 continue;
249                         } 
250                 }
251                 p->write(wi);
252         }
253 }
254
255
256 void normalize(MathArray const & ar, NormalStream & os)
257 {
258         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
259                 (*it)->normalize(os);
260 }
261
262
263 void octavize(MathArray const & dat, OctaveStream & os)
264 {
265         MathArray ar = dat;
266         extractStructure(ar);
267         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
268                 MathInset const * p = it->nucleus();
269                 if (it + 1 != ar.end()) {
270                         if (MathScriptInset const * q = asScript(it)) {
271                                 q->octavize(p, os);
272                                 ++it;   
273                                 continue;
274                         }
275                 }
276                 p->octavize(os);
277         }
278 }
279
280
281 void maplize(MathArray const & dat, MapleStream & os)
282 {
283         MathArray ar = dat;
284         extractStructure(ar);
285         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
286                 MathInset const * p = it->nucleus();
287                 if (it + 1 != ar.end()) {
288                         if (MathScriptInset const * q = asScript(it)) {
289                                 q->maplize(p, os);
290                                 ++it;   
291                                 continue;
292                         }
293                 }
294                 p->maplize(os);
295         }
296 }
297
298
299 void mathmlize(MathArray const & dat, MathMLStream & os)
300 {
301         MathArray ar = dat;
302         extractStructure(ar);
303         if (ar.size() == 0)
304                 os << "<mrow/>";
305         else if (ar.size() == 1)
306                 os << ar.begin()->nucleus();
307         else {
308                 os << MTag("mrow");
309                 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
310                         MathInset const * p = it->nucleus();
311                         if (it + 1 != ar.end()) {
312                                 if (MathScriptInset const * q = asScript(it)) {
313                                         q->mathmlize(p, os);
314                                         ++it;   
315                                         continue;
316                                 }
317                         }
318                         p->mathmlize(os);
319                 }
320                 os << ETag("mrow");
321         }
322 }
323