]> git.lyx.org Git - lyx.git/blob - src/mathed/MathFactory.cpp
Display equation/theorem numbers in insert cross reference dialog.
[lyx.git] / src / mathed / MathFactory.cpp
1 /**
2  * \file MathFactory.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "MathFactory.h"
14
15 #include "InsetMathAMSArray.h"
16 #include "InsetMathArray.h"
17 #include "InsetMathBoldSymbol.h"
18 #include "InsetMathBox.h"
19 #include "InsetMathCancel.h"
20 #include "InsetMathCancelto.h"
21 #include "InsetMathCases.h"
22 #include "InsetMathClass.h"
23 #include "InsetMathColor.h"
24 #include "InsetMathDecoration.h"
25 #include "InsetMathDots.h"
26 #include "InsetMathEnsureMath.h"
27 #include "InsetMathFont.h"
28 #include "InsetMathFontOld.h"
29 #include "InsetMathFrac.h"
30 #include "InsetMathKern.h"
31 #include "InsetMathLefteqn.h"
32 #include "InsetMathOverset.h"
33 #include "InsetMathPhantom.h"
34 #include "InsetMathRef.h"
35 #include "InsetMathRoot.h"
36 #include "InsetMathSideset.h"
37 #include "InsetMathSize.h"
38 #include "InsetMathSpace.h"
39 #include "InsetMathSpecialChar.h"
40 #include "InsetMathSplit.h"
41 #include "InsetMathSqrt.h"
42 #include "InsetMathStackrel.h"
43 #include "InsetMathSubstack.h"
44 #include "InsetMathSymbol.h"
45 #include "InsetMathTabular.h"
46 #include "InsetMathUnderset.h"
47 #include "InsetMathUnknown.h"
48 #include "InsetMathHull.h"
49 #include "InsetMathXArrow.h"
50 #include "InsetMathXYMatrix.h"
51 #include "InsetMathDiagram.h"
52 #include "MacroTable.h"
53 #include "InsetMathMacro.h"
54 #include "InsetMathMacroArgument.h"
55 #include "MathParser.h"
56 #include "MathStream.h"
57 #include "MathSupport.h"
58
59 #include "insets/InsetCommand.h"
60 #include "insets/InsetSpace.h"
61
62 #include "support/debug.h"
63 #include "support/docstream.h"
64 #include "support/FileName.h"
65 #include "support/filetools.h" // LibFileSearch
66 #include "support/lstrings.h"
67 #include "support/textutils.h"
68
69 #include "frontends/FontLoader.h"
70
71 #include "Buffer.h"
72 #include "BufferParams.h"
73 #include "Encoding.h"
74 #include "FontInfo.h"
75 #include "LyX.h" // use_gui
76
77 #include <iomanip>
78
79 using namespace std;
80 using namespace lyx::support;
81
82 namespace lyx {
83
84 bool has_math_fonts;
85
86
87 namespace {
88
89 MathWordList theMathWordList;
90
91
92 bool isMathFontAvailable(string & name)
93 {
94         if (!use_gui)
95                 return false;
96
97         FontInfo f;
98         augmentFont(f, name);
99
100         // Do we have the font proper?
101         if (theFontLoader().available(f))
102                 return true;
103
104         // can we fake it?
105         if (name == "eufrak") {
106                 name = "lyxfakefrak";
107                 return true;
108         }
109
110         LYXERR(Debug::MATHED,
111                 "font " << name << " not available and I can't fake it");
112         return false;
113 }
114
115
116 bool canBeDisplayed(char_type c)
117 {
118         if (!use_gui)
119                 return true;
120         return theFontLoader().canBeDisplayed(c);
121 }
122
123
124 bool isUnicodeSymbolAvailable(docstring const & name, char_type & c)
125 {
126         docstring cmd(from_ascii("\\") + name);
127         bool is_combining;
128         bool termination;
129         c = Encodings::fromLaTeXCommand(cmd, Encodings::MATH_CMD,
130                                         is_combining, termination);
131         if (c == 0 && name == "varOmega") {
132                 // fallback for bug 7954, unicodesymbols does not list
133                 // \\varOmega because of requirements, but this might change
134                 cmd = from_ascii("\\mathit{\\Omega}");
135                 c = Encodings::fromLaTeXCommand(cmd, Encodings::MATH_CMD,
136                                                 is_combining, termination);
137         }
138         return c != 0 && !is_combining;
139 }
140
141
142 void initSymbols()
143 {
144         FileName const filename = libFileSearch(string(), "symbols");
145         LYXERR(Debug::MATHED, "read symbols from " << filename);
146         if (filename.empty()) {
147                 lyxerr << "Could not find symbols file" << endl;
148                 return;
149         }
150
151         ifstream fs(filename.toFilesystemEncoding().c_str());
152         // limit the size of strings we read to avoid memory problems
153         fs >> setw(65636);
154         string line;
155         bool skip = false;
156         while (getline(fs, line)) {
157                 int charid     = 0;
158                 int dsp_charid = 0;
159                 int fallbackid = 0;
160                 if (line.empty() || line[0] == '#')
161                         continue;
162
163                 // special case of iffont/else/endif
164                 if (line.size() >= 7 && line.substr(0, 6) == "iffont") {
165                         istringstream is(line);
166                         // limit the size of strings we read to avoid memory problems
167                         is >> setw(65636);
168                         string tmp;
169                         is >> tmp;
170                         is >> tmp;
171                         skip = !isMathFontAvailable(tmp);
172                         continue;
173                 } else if (line.size() >= 4 && line.substr(0, 4) == "else") {
174                         skip = !skip;
175                         continue;
176                 } else if (line.size() >= 5 && line.substr(0, 5) == "endif") {
177                         skip = false;
178                         continue;
179                 } else if (skip)
180                         continue;
181
182                 // special case of pre-defined macros
183                 if (line.size() > 8 && line.substr(0, 5) == "\\def\\") {
184                         //lyxerr << "macro definition: '" << line << '\'' << endl;
185                         // syntax: Either
186                         // \def\macroname{definition}
187                         // or
188                         // \def\macroname{definition} requires
189                         // or
190                         // \def\macroname{definition} extra xmlname requires
191                         istringstream is(line);
192                         string macro;
193                         string required;
194                         string extra;
195                         string xmlname;
196                         bool hidden = false;
197                         is >> setw(65536) >> macro >> required;
198                         if ((is >> xmlname)) {
199                                 extra = required;
200                                 if (!(is >> required))
201                                         required = "";
202                         } else
203                                 xmlname = "";
204                         MacroTable::iterator it = MacroTable::globalMacros().insert(
205                                         nullptr, from_utf8(macro));
206                         if (!extra.empty() || !xmlname.empty() || !required.empty()) {
207                                 MathWordList::iterator wit = theMathWordList.find(it->first);
208                                 if (wit != theMathWordList.end())
209                                         LYXERR(Debug::MATHED, "readSymbols: inset "
210                                                 << to_utf8(it->first) << " already exists.");
211                                 else {
212                                         latexkeys tmp;
213                                         tmp.inset = "macro";
214                                         tmp.name = it->first;
215                                         tmp.extra = from_utf8(extra);
216                                         tmp.xmlname = from_utf8(xmlname);
217                                         if (required == "hiddensymbol") {
218                                                 required = "";
219                                                 tmp.hidden = hidden = true;
220                                         } else
221                                                 tmp.required = required;
222                                         theMathWordList[it->first] = tmp;
223                                         wit = theMathWordList.find(it->first);
224                                         it->second.setSymbol(&(wit->second));
225                                 }
226                         }
227                         // If you change the following output, please adjust
228                         // development/tools/generate_symbols_images.py.
229                         LYXERR(Debug::MATHED, "read symbol '" << to_utf8(it->first)
230                             << "  inset: macro"
231                             << "  draw: 0"
232                             << "  extra: " << extra
233                             << "  xml: " << xmlname
234                                 << "  requires: " << required
235                                 << "  hidden: " << hidden << '\'');
236                         continue;
237                 }
238
239                 idocstringstream is(from_utf8(line));
240                 latexkeys tmp;
241                 docstring help;
242                 is >> tmp.name >> help;
243                 tmp.inset = to_ascii(help);
244                 if (isFontName(tmp.inset)) {
245                         is >> help >> fallbackid >> tmp.extra >> tmp.xmlname;
246                         docstring cid, dsp_cid;
247                         idocstringstream is2(subst(help, '|', ' '));
248                         is2 >> charid >> dsp_charid;
249                 } else
250                         is >> tmp.extra;
251                 // requires is optional
252                 if (is) {
253                         if ((is >> help)) {
254                                 // backward compatibility
255                                 if (help == "esintoramsmath")
256                                         tmp.required = "esint|amsmath";
257                                 else
258                                         tmp.required = to_ascii(help);
259                         }
260                 } else {
261                         LYXERR(Debug::MATHED, "skipping line '" << line << "'\n"
262                                 << to_utf8(tmp.name) << ' ' << tmp.inset << ' '
263                                 << to_utf8(tmp.extra));
264                         continue;
265                 }
266
267                 if (isFontName(tmp.inset)) {
268                         // tmp.inset _is_ the fontname here.
269                         // create fallbacks if necessary
270
271                         // store requirements as long as we can
272                         if (tmp.required.empty()) {
273                                 if (tmp.inset == "msa" || tmp.inset == "msb")
274                                         tmp.required = "amssymb";
275                                 else if (tmp.inset == "wasy")
276                                         tmp.required = "wasysym";
277                                 else if (tmp.inset == "mathscr")
278                                         tmp.required = "mathrsfs";
279                                 else if (tmp.inset == "mathds")
280                                         tmp.required = "dsfont";
281                         }
282
283                         // symbol font is not available sometimes
284                         string symbol_font = "lyxsymbol";
285                         char_type unicodesymbol = 0;
286
287                         if (tmp.extra == "func" || tmp.extra == "funclim" || tmp.extra == "special") {
288                                 LYXERR(Debug::MATHED, "symbol abuse for " << to_utf8(tmp.name));
289                                 tmp.draw = tmp.name;
290                         } else if (isMathFontAvailable(tmp.inset) && canBeDisplayed(charid)) {
291                                 LYXERR(Debug::MATHED, "symbol available for " << to_utf8(tmp.name));
292                                 tmp.draw.push_back(char_type(charid));
293                                 if (dsp_charid && canBeDisplayed(dsp_charid)) {
294                                         LYXERR(Debug::MATHED, "large symbol available for " << to_utf8(tmp.name));
295                                         tmp.dsp_draw.push_back(char_type(dsp_charid));
296                                 }
297                         } else if (fallbackid && isMathFontAvailable(symbol_font) &&
298                                    canBeDisplayed(fallbackid)) {
299                                 if (tmp.inset == "cmex")
300                                         tmp.inset = "lyxsymbol";
301                                 else
302                                         tmp.inset = "lyxboldsymbol";
303                                 LYXERR(Debug::MATHED, "symbol fallback for " << to_utf8(tmp.name));
304                                 tmp.draw.push_back(char_type(fallbackid));
305                         } else if (isUnicodeSymbolAvailable(tmp.name, unicodesymbol)) {
306                                 LYXERR(Debug::MATHED, "unicode fallback for " << to_utf8(tmp.name));
307                                 tmp.inset = "mathnormal";
308                                 tmp.draw.push_back(unicodesymbol);
309                         } else {
310                                 LYXERR(Debug::MATHED, "faking " << to_utf8(tmp.name));
311                                 tmp.draw = tmp.name;
312                                 tmp.inset = "lyxtex";
313                         }
314                 } else {
315                         // it's a proper inset
316                         LYXERR(Debug::MATHED, "inset " << tmp.inset
317                                               << " used for " << to_utf8(tmp.name));
318                 }
319
320                 if (tmp.required == "hiddensymbol")
321                 {
322                         tmp.required = "";
323                         tmp.hidden = true;
324                 }
325
326                 if (theMathWordList.find(tmp.name) != theMathWordList.end())
327                         LYXERR(Debug::MATHED, "readSymbols: inset " << to_utf8(tmp.name)
328                                 << " already exists.");
329                 else
330                         theMathWordList[tmp.name] = tmp;
331
332                 // If you change the following output, please adjust
333                 // development/tools/generate_symbols_images.py.
334                 LYXERR(Debug::MATHED, "read symbol '" << to_utf8(tmp.name)
335                         << "  inset: " << tmp.inset
336                         << "  draw: " << int(tmp.draw.empty() ? 0 : tmp.draw[0])
337                         << "  extra: " << to_utf8(tmp.extra)
338                         << "  xml: " << to_utf8(tmp.xmlname)
339                         << "  requires: " << tmp.required
340                         << "  hidden: " << tmp.hidden << '\'');
341         }
342         string tmp = "cmm";
343         string tmp2 = "cmsy";
344         has_math_fonts = isMathFontAvailable(tmp) && isMathFontAvailable(tmp2);
345 }
346
347
348 bool isSpecialChar(docstring const & name)
349 {
350         if (name.size() != 1)
351                 return  name == "textasciicircum" || name == "mathcircumflex" ||
352                         name == "textasciitilde"  || name == "textbackslash";
353
354         char_type const c = name.at(0);
355         return  c == '{' || c == '}' || c == '&' || c == '$' ||
356                 c == '#' || c == '%' || c == '_';
357 }
358
359
360 } // namespace
361
362 MathWordList const & mathedWordList()
363 {
364         return theMathWordList;
365 }
366
367
368 void initMath()
369 {
370         static bool initialized = false;
371         if (!initialized) {
372                 initialized = true;
373                 initParser();
374                 initSymbols();
375         }
376 }
377
378
379 bool ensureMath(TeXMathStream & os, bool needs_mathmode, bool macro,
380                 bool textmode_macro)
381 {
382         bool brace = os.pendingBrace();
383         os.pendingBrace(false);
384         if (!os.latex())
385                 return brace;
386         if (os.textMode() && needs_mathmode) {
387                 if (brace) {
388                         // close \lyxmathsym
389                         os << '}';
390                         brace = false;
391                 } else {
392                         os << "\\ensuremath{";
393                         brace = true;
394                 }
395                 os.textMode(false);
396         } else if (macro && textmode_macro && !os.textMode()) {
397                 if (brace) {
398                         // close \ensuremath
399                         os << '}';
400                         brace = false;
401                 } else {
402                         os << "\\lyxmathsym{";
403                         brace = true;
404                 }
405                 os.textMode(true);
406         } else if (macro && brace && !needs_mathmode && !textmode_macro) {
407                 // This is a user defined macro, not a InsetMathMacro, so we
408                 // cannot be sure what mode is needed. We leave it in the
409                 // same environment it was entered by closing either \lyxmathsym
410                 // or \ensuremath, whichever was opened.
411                 os << '}';
412                 brace = false;
413                 os.textMode(!os.textMode());
414         }
415         return brace;
416 }
417
418
419 int ensureMode(TeXMathStream & os, InsetMath::mode_type mode,
420                bool locked, bool ascii)
421 {
422         bool textmode = mode == InsetMath::TEXT_MODE;
423         if (os.latex() && textmode && os.pendingBrace()) {
424                 os.os() << '}';
425                 os.pendingBrace(false);
426                 os.pendingSpace(false);
427                 os.textMode(true);
428         }
429         int oldmodes = os.textMode() ? 0x01 : 0;
430         os.textMode(textmode);
431         oldmodes |= os.lockedMode() ? 0x02 : 0;
432         os.lockedMode(locked);
433         oldmodes |= os.asciiOnly() ? 0x04 : 0;
434         os.asciiOnly(ascii);
435         return oldmodes;
436 }
437
438
439 latexkeys const * in_word_set(docstring const & str)
440 {
441         MathWordList::iterator it = theMathWordList.find(str);
442         if (it == theMathWordList.end())
443                 return nullptr;
444         if (it->second.inset == "macro")
445                 return nullptr;
446         return &(it->second);
447 }
448
449
450 MathAtom createInsetMath(char const * const s, Buffer * buf)
451 {
452         return createInsetMath(from_utf8(s), buf);
453 }
454
455
456 MathAtom createInsetMath(docstring const & s, Buffer * buf)
457 {
458         //lyxerr << "creating inset with name: '" << to_utf8(s) << '\'' << endl;
459         if ((s == "ce" || s == "cf") && buf
460             && buf->params().use_package("mhchem") == BufferParams::package_off)
461                 return MathAtom(new InsetMathMacro(buf, s));
462
463         latexkeys const * l = in_word_set(s);
464         if (l) {
465                 string const & inset = l->inset;
466                 //lyxerr << " found inset: '" << inset << '\'' << endl;
467                 if (inset == "ref")
468                         return MathAtom(new InsetMathRef(buf, l->name));
469                 if (inset == "overset")
470                         return MathAtom(new InsetMathOverset(buf));
471                 if (inset == "underset")
472                         return MathAtom(new InsetMathUnderset(buf));
473                 if (inset == "decoration")
474                         return MathAtom(new InsetMathDecoration(buf, l));
475                 if (inset == "space")
476                         return MathAtom(new InsetMathSpace(to_ascii(l->name), ""));
477                 if (inset == "class")
478                         return MathAtom(new InsetMathClass(buf, string_to_class(s)));
479                 if (inset == "dots")
480                         return MathAtom(new InsetMathDots(l));
481                 if (inset == "mbox")
482                         return MathAtom(new InsetMathBox(buf, l->name));
483 //              if (inset == "fbox")
484 //                      return MathAtom(new InsetMathFBox(l));
485                 if (inset == "style")
486                         return MathAtom(new InsetMathSize(buf, l));
487                 if (inset == "font")
488                         return MathAtom(new InsetMathFont(buf, l));
489                 if (inset == "oldfont")
490                         return MathAtom(new InsetMathFontOld(buf, l));
491                 if (inset == "matrix")
492                         return MathAtom(new InsetMathAMSArray(buf, s));
493                 if (inset == "split")
494                         return MathAtom(new InsetMathSplit(buf, s));
495                 if (inset == "big")
496                         // we can't create a InsetMathBig, since the argument
497                         // is missing.
498                         return MathAtom(new InsetMathUnknown(s));
499                 return MathAtom(new InsetMathSymbol(l));
500         }
501
502         if (s.size() == 2 && s[0] == '#' && s[1] >= '1' && s[1] <= '9')
503                 return MathAtom(new InsetMathMacroArgument(s[1] - '0'));
504         if (s.size() == 3 && s[0] == '\\' && s[1] == '#'
505                         && s[2] >= '1' && s[2] <= '9')
506                 return MathAtom(new InsetMathMacroArgument(s[2] - '0'));
507         if (s == "boxed")
508                 return MathAtom(new InsetMathBoxed(buf));
509         if (s == "fbox")
510                 return MathAtom(new InsetMathFBox(buf));
511         if (s == "framebox")
512                 return MathAtom(new InsetMathMakebox(buf, true));
513         if (s == "makebox")
514                 return MathAtom(new InsetMathMakebox(buf, false));
515         if (s.substr(0, 8) == "xymatrix") {
516                 char spacing_code = '\0';
517                 Length spacing;
518                 bool equal_spacing = false;
519                 size_t const len = s.length();
520                 size_t i = 8;
521                 if (i < len && s[i] == '@') {
522                         ++i;
523                         if (i < len && s[i] == '!') {
524                                 equal_spacing = true;
525                                 ++i;
526                                 if (i < len) {
527                                         switch (s[i]) {
528                                         case '0':
529                                         case 'R':
530                                         case 'C':
531                                                 spacing_code = static_cast<char>(s[i]);
532                                         }
533                                 }
534                         } else if (i < len) {
535                                 switch (s[i]) {
536                                 case 'R':
537                                 case 'C':
538                                 case 'M':
539                                 case 'W':
540                                 case 'H':
541                                 case 'L':
542                                         spacing_code = static_cast<char>(s[i]);
543                                         ++i;
544                                         break;
545                                 }
546                                 if (i < len && s[i] == '=') {
547                                         ++i;
548                                         spacing = Length(to_ascii(s.substr(i)));
549                                 }
550                         }
551                 }
552                 return MathAtom(new InsetMathXYMatrix(buf, spacing, spacing_code,
553                         equal_spacing));
554         }
555
556         if (s == "Diagram")
557                 return MathAtom(new InsetMathDiagram(buf));
558         if (s == "xrightarrow" || s == "xleftarrow" ||
559                 s == "xhookrightarrow" || s == "xhookleftarrow" ||
560                 s == "xRightarrow" || s == "xLeftarrow" ||
561                 s == "xleftrightarrow" || s == "xLeftrightarrow" ||
562                 s == "xrightharpoondown" || s == "xrightharpoonup" ||
563                 s == "xleftharpoondown" || s == "xleftharpoonup" ||
564                 s == "xleftrightharpoons" || s == "xrightleftharpoons" ||
565                 s == "xmapsto")
566                 return MathAtom(new InsetMathXArrow(buf, s));
567         if (s == "split" || s == "alignedat")
568                 return MathAtom(new InsetMathSplit(buf, s));
569         if (s == "cases")
570                 return MathAtom(new InsetMathCases(buf));
571         if (s == "substack")
572                 return MathAtom(new InsetMathSubstack(buf));
573         if (s == "subarray" || s == "array")
574                 return MathAtom(new InsetMathArray(buf, s, 1, 1));
575         if (s == "sqrt")
576                 return MathAtom(new InsetMathSqrt(buf));
577         if (s == "root")
578                 return MathAtom(new InsetMathRoot(buf));
579         if (s == "tabular")
580                 return MathAtom(new InsetMathTabular(buf, s, 1, 1));
581         if (s == "stackrel")
582                 return MathAtom(new InsetMathStackrel(buf, false));
583         // This string value is only for math toolbar use, no LaTeX name
584         if (s == "stackrelthree")
585                 return MathAtom(new InsetMathStackrel(buf, true));
586         if (s == "binom")
587                 return MathAtom(new InsetMathBinom(buf, InsetMathBinom::BINOM));
588         if (s == "dbinom")
589                 return MathAtom(new InsetMathBinom(buf, InsetMathBinom::DBINOM));
590         if (s == "tbinom")
591                 return MathAtom(new InsetMathBinom(buf, InsetMathBinom::TBINOM));
592         if (s == "choose")
593                 return MathAtom(new InsetMathBinom(buf, InsetMathBinom::CHOOSE));
594         if (s == "brace")
595                 return MathAtom(new InsetMathBinom(buf, InsetMathBinom::BRACE));
596         if (s == "brack")
597                 return MathAtom(new InsetMathBinom(buf, InsetMathBinom::BRACK));
598         if (s == "frac")
599                 return MathAtom(new InsetMathFrac(buf));
600         if (s == "cfrac")
601                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRAC));
602         if (s == "dfrac")
603                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::DFRAC));
604         if (s == "tfrac")
605                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::TFRAC));
606         if (s == "over")
607                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::OVER));
608         if (s == "nicefrac")
609                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::NICEFRAC));
610         if (s == "unitfrac")
611                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNITFRAC));
612         // These string values are only for math toolbar use, no LaTeX names
613         if (s == "unitfracthree")
614                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNITFRAC, 3));
615         if (s == "unitone")
616                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNIT, 1));
617         if (s == "unittwo")
618                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNIT));
619         if (s == "cfracleft")
620                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACLEFT));
621         if (s == "cfracright")
622                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACRIGHT));
623         if (s == "case") // TODO: only if class is aastex(6|62)
624                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::AASTEX_CASE));
625         //if (s == "infer")
626         //      return MathAtom(new MathInferInset);
627         if (s == "atop")
628                 return MathAtom(new InsetMathFrac(buf, InsetMathFrac::ATOP));
629         if (s == "lefteqn")
630                 return MathAtom(new InsetMathLefteqn(buf));
631         if (s == "boldsymbol")
632                 return MathAtom(new InsetMathBoldSymbol(buf, InsetMathBoldSymbol::AMS_BOLD));
633         if (s == "bm")
634                 return MathAtom(new InsetMathBoldSymbol(buf, InsetMathBoldSymbol::BM_BOLD));
635         if (s == "heavysymbol" || s == "hm")
636                 return MathAtom(new InsetMathBoldSymbol(buf, InsetMathBoldSymbol::BM_HEAVY));
637         if (s == "color" || s == "normalcolor")
638                 return MathAtom(new InsetMathColor(buf, true));
639         if (s == "textcolor")
640                 return MathAtom(new InsetMathColor(buf, false));
641         if (s == "hphantom")
642                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::hphantom));
643         if (s == "phantom")
644                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::phantom));
645         if (s == "vphantom")
646                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::vphantom));
647         if (s == "cancel")
648                 return MathAtom(new InsetMathCancel(buf, InsetMathCancel::cancel));
649         if (s == "bcancel")
650                 return MathAtom(new InsetMathCancel(buf, InsetMathCancel::bcancel));
651         if (s == "xcancel")
652                 return MathAtom(new InsetMathCancel(buf, InsetMathCancel::xcancel));
653         if (s == "cancelto")
654                 return MathAtom(new InsetMathCancelto(buf));
655         if (s == "smash")
656                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::smash));
657         // The following 2 string values are only for math toolbar use, no LaTeX names
658         if (s == "smashb")
659                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::smashb));
660         if (s == "smasht")
661                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::smasht));
662         if (s == "mathclap")
663                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::mathclap));
664         if (s == "mathllap")
665                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::mathllap));
666         if (s == "mathrlap")
667                 return MathAtom(new InsetMathPhantom(buf, InsetMathPhantom::mathrlap));
668         if (s == "ensuremath")
669                 return MathAtom(new InsetMathEnsureMath(buf));
670         if (s == "sideset")
671                 return MathAtom(new InsetMathSideset(buf, true, true));
672         // The following 3 string values are only for math toolbar use, no LaTeX names
673         if (s == "sidesetr")
674                 return MathAtom(new InsetMathSideset(buf, false, true));
675         if (s == "sidesetl")
676                 return MathAtom(new InsetMathSideset(buf, true, false));
677         if (s == "sidesetn")
678                 return MathAtom(new InsetMathSideset(buf, false, false));
679         if (isSpecialChar(s))
680                 return MathAtom(new InsetMathSpecialChar(s));
681         if (s == " ")
682                 return MathAtom(new InsetMathSpace(" ", ""));
683         if (s == "regexp")
684                 return MathAtom(new InsetMathHull(buf, hullRegexp));
685
686         return MathAtom(new InsetMathMacro(buf, s));
687 }
688
689
690 bool createInsetMath_fromDialogStr(docstring const & str, MathData & ar)
691 {
692         // An example str:
693         // "ref LatexCommand ref\nreference \"sec:Title\"\n\\end_inset\n\n";
694         docstring name;
695         docstring body = split(str, name, ' ');
696
697         if (name == "ref") {
698                 InsetCommandParams icp(REF_CODE);
699                 // FIXME UNICODE
700                 InsetCommand::string2params(to_utf8(str), icp);
701                 Encoding const * const utf8 = encodings.fromLyXName("utf8");
702                 OutputParams op(utf8);
703                 mathed_parse_cell(ar, icp.getCommand(op));
704         } else if (name == "mathspace") {
705                 InsetSpaceParams isp(true);
706                 InsetSpace::string2params(to_utf8(str), isp);
707                 InsetSpace is(isp);
708                 odocstringstream ods;
709                 otexstream os(ods);
710                 Encoding const * const ascii = encodings.fromLyXName("ascii");
711                 OutputParams op(ascii);
712                 is.latex(os, op);
713                 mathed_parse_cell(ar, ods.str());
714                 if (ar.size() == 2) {
715                         // remove "{}"
716                         if (ar[1].nucleus()->asBraceInset())
717                                 ar.pop_back();
718                 }
719         } else
720                 return false;
721
722         if (ar.size() != 1)
723                 return false;
724
725         return ar[0].nucleus();
726 }
727
728
729 } // namespace lyx