]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
fix mathed crash
[lyx.git] / src / LaTeXFeatures.C
1 /**
2  * \file LaTeXFeatures.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "bufferparams.h"
20 #include "debug.h"
21 #include "encoding.h"
22 #include "Floating.h"
23 #include "FloatList.h"
24 #include "language.h"
25 #include "lyx_sty.h"
26 #include "lyxrc.h"
27
28 #include "support/filetools.h"
29
30 #include "support/std_sstream.h"
31
32 using lyx::support::IsSGMLFilename;
33 using lyx::support::MakeRelPath;
34 using lyx::support::OnlyPath;
35
36 using std::endl;
37 using std::find;
38 using std::string;
39 using std::list;
40 using std::ostream;
41 using std::ostringstream;
42 using std::set;
43
44
45 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p, bool n)
46         : buffer_(b), params_(p), nice_(n)
47 {}
48
49
50 bool LaTeXFeatures::useBabel() const
51 {
52         return lyxrc.language_use_babel ||
53                 bufferParams().language->lang() != lyxrc.default_language ||
54                 this->hasLanguages();
55 }
56
57
58 void LaTeXFeatures::require(string const & name)
59 {
60         if (isRequired(name))
61                 return;
62
63         features_.push_back(name);
64 }
65
66
67 void LaTeXFeatures::useLayout(string const & layoutname)
68 {
69         // Some code to avoid loops in dependency definition
70         static int level = 0;
71         const int maxlevel = 30;
72         if (level > maxlevel) {
73                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
74                        << "recursion attained by layout "
75                        << layoutname << endl;
76                 return;
77         }
78
79         LyXTextClass const & tclass = params_.getLyXTextClass();
80         if (tclass.hasLayout(layoutname)) {
81                 // Is this layout already in usedLayouts?
82                 list<string>::const_iterator cit = usedLayouts_.begin();
83                 list<string>::const_iterator end = usedLayouts_.end();
84                 for (; cit != end; ++cit) {
85                         if (layoutname == *cit)
86                                 return;
87                 }
88
89                 LyXLayout_ptr const & lyt = tclass[layoutname];
90                 if (!lyt->depends_on().empty()) {
91                         ++level;
92                         useLayout(lyt->depends_on());
93                         --level;
94                 }
95                 usedLayouts_.push_back(layoutname);
96         } else {
97                 lyxerr << "LaTeXFeatures::useLayout: layout `"
98                        << layoutname << "' does not exist in this class"
99                        << endl;
100         }
101
102         --level;
103 }
104
105
106 bool LaTeXFeatures::isRequired(string const & name) const
107 {
108         return find(features_.begin(), features_.end(), name) != features_.end();
109 }
110
111
112 void LaTeXFeatures::addExternalPreamble(string const & preamble)
113 {
114         FeaturesList::const_iterator begin = preamble_snippets_.begin();
115         FeaturesList::const_iterator end   = preamble_snippets_.end();
116         if (find(begin, end, preamble) == end)
117                 preamble_snippets_.push_back(preamble);
118 }
119
120
121 void LaTeXFeatures::useFloat(string const & name)
122 {
123         usedFloats_.insert(name);
124         // We only need float.sty if we use non builtin floats, or if we
125         // use the "H" modifier. This includes modified table and
126         // figure floats. (Lgb)
127         Floating const & fl = params_.getLyXTextClass().floats().getType(name);
128         if (!fl.type().empty() && !fl.builtin()) {
129                 require("float");
130         }
131 }
132
133
134 void LaTeXFeatures::useLanguage(Language const * lang)
135 {
136         UsedLanguages_.insert(lang);
137 }
138
139
140 void LaTeXFeatures::includeFile(string const & key, string const & name)
141 {
142         IncludedFiles_[key] = name;
143 }
144
145
146 bool LaTeXFeatures::hasLanguages() const
147 {
148         return !UsedLanguages_.empty();
149 }
150
151
152 string LaTeXFeatures::getLanguages() const
153 {
154         ostringstream languages;
155
156         for (LanguageList::const_iterator cit =
157                     UsedLanguages_.begin();
158              cit != UsedLanguages_.end();
159              ++cit)
160                 languages << (*cit)->babel() << ',';
161
162         return languages.str();
163 }
164
165
166 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
167 {
168         set<string> encodings;
169         LanguageList::const_iterator it  = UsedLanguages_.begin();
170         LanguageList::const_iterator end = UsedLanguages_.end();
171         for (; it != end; ++it)
172                 if ((*it)->encoding()->LatexName() != doc_encoding)
173                         encodings.insert((*it)->encoding()->LatexName());
174         return encodings;
175 }
176
177 namespace {
178
179 char const * simplefeatures[] = {
180         "array",
181         "verbatim",
182         "longtable",
183         "rotating",
184         "latexsym",
185         "pifont",
186         "subfigure",
187         "floatflt",
188         "varioref",
189         "prettyref",
190         "float",
191         "wasy",
192         "dvipost",
193         "fancybox",
194         "calc"
195 };
196
197 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
198
199 }
200
201
202 string const LaTeXFeatures::getPackages() const
203 {
204         ostringstream packages;
205         LyXTextClass const & tclass = params_.getLyXTextClass();
206
207         //
208         //  These are all the 'simple' includes.  i.e
209         //  packages which we just \usepackage{package}
210         //
211         for (int i = 0; i < nb_simplefeatures; ++i) {
212                 if (isRequired(simplefeatures[i]))
213                         packages << "\\usepackage{"
214                                  << simplefeatures[i] << "}\n";
215         }
216
217         //
218         // The rest of these packages are somewhat more complicated
219         // than those above.
220         //
221
222         if (isRequired("amsmath")
223             && !tclass.provides(LyXTextClass::amsmath)
224             && params_.use_amsmath != BufferParams::AMS_OFF) {
225                 packages << "\\usepackage{amsmath}\n";
226         }
227
228         // color.sty
229         if (isRequired("color")) {
230                 if (params_.graphicsDriver == "default")
231                         packages << "\\usepackage[usenames]{color}\n";
232                 else
233                         packages << "\\usepackage["
234                                  << params_.graphicsDriver
235                                  << ",usenames"
236                                  << "]{color}\n";
237         }
238
239         // makeidx.sty
240         if (isRequired("makeidx")) {
241                 if (! tclass.provides(LyXTextClass::makeidx))
242                         packages << "\\usepackage{makeidx}\n";
243                 packages << "\\makeindex\n";
244         }
245
246         // graphicx.sty
247         if (isRequired("graphicx") && params_.graphicsDriver != "none") {
248                 if (params_.graphicsDriver == "default")
249                         packages << "\\usepackage{graphicx}\n";
250                 else
251                         packages << "\\usepackage["
252                                  << params_.graphicsDriver
253                                  << "]{graphicx}\n";
254         }
255
256         //if (algorithm) {
257         //      packages << "\\usepackage{algorithm}\n";
258         //}
259
260         // lyxskak.sty --- newer chess support based on skak.sty
261         if (isRequired("chess")) {
262                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
263         }
264
265         // setspace.sty
266         if ((params_.spacing().getSpace() != Spacing::Single
267              && !params_.spacing().isDefault())
268             || isRequired("setspace")) {
269                 packages << "\\usepackage{setspace}\n";
270         }
271         switch (params_.spacing().getSpace()) {
272         case Spacing::Default:
273         case Spacing::Single:
274                 // we dont use setspace.sty so dont print anything
275                 //packages += "\\singlespacing\n";
276                 break;
277         case Spacing::Onehalf:
278                 packages << "\\onehalfspacing\n";
279                 break;
280         case Spacing::Double:
281                 packages << "\\doublespacing\n";
282                 break;
283         case Spacing::Other:
284                 packages << "\\setstretch{"
285                          << params_.spacing().getValue() << "}\n";
286                 break;
287         }
288
289         // amssymb.sty
290         if (isRequired("amssymb") || params_.use_amsmath == BufferParams::AMS_ON)
291                 packages << "\\usepackage{amssymb}\n";
292         // url.sty
293         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
294                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
295                             "                      {\\newcommand{\\url}{\\texttt}}\n";
296
297         // float.sty
298         // natbib.sty
299         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
300                 packages << "\\usepackage[";
301                 if (params_.use_numerical_citations) {
302                         packages << "numbers";
303                 } else {
304                         packages << "authoryear";
305                 }
306                 packages << "]{natbib}\n";
307         }
308
309         return packages.str();
310 }
311
312
313 string const LaTeXFeatures::getMacros() const
314 {
315         ostringstream macros;
316
317         if (!preamble_snippets_.empty())
318                 macros << '\n';
319         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
320         FeaturesList::const_iterator pend = preamble_snippets_.end();
321         for (; pit != pend; ++pit) {
322                 macros << *pit << '\n';
323         }
324
325         if (isRequired("LyX"))
326                 macros << lyx_def << '\n';
327
328         if (isRequired("lyxline"))
329                 macros << lyxline_def << '\n';
330
331         if (isRequired("noun"))
332                 macros << noun_def << '\n';
333
334         if (isRequired("lyxarrow"))
335                 macros << lyxarrow_def << '\n';
336
337         // quotes.
338         if (isRequired("quotesinglbase"))
339                 macros << quotesinglbase_def << '\n';
340         if (isRequired("quotedblbase"))
341                 macros << quotedblbase_def << '\n';
342         if (isRequired("guilsinglleft"))
343                 macros << guilsinglleft_def << '\n';
344         if (isRequired("guilsinglright"))
345                 macros << guilsinglright_def << '\n';
346         if (isRequired("guillemotleft"))
347                 macros << guillemotleft_def << '\n';
348         if (isRequired("guillemotright"))
349                 macros << guillemotright_def << '\n';
350
351         // Math mode
352         if (isRequired("boldsymbol") && !isRequired("amsmath"))
353                 macros << boldsymbol_def << '\n';
354         if (isRequired("binom") && !isRequired("amsmath"))
355                 macros << binom_def << '\n';
356         if (isRequired("mathcircumflex"))
357                 macros << mathcircumflex_def << '\n';
358
359         // other
360         if (isRequired("ParagraphLeftIndent"))
361                 macros << paragraphleftindent_def;
362         if (isRequired("NeedLyXFootnoteCode"))
363                 macros << floatingfootnote_def;
364
365         // some problems with tex->html converters
366         if (isRequired("NeedTabularnewline"))
367                 macros << tabularnewline_def;
368
369         // greyedout environment (note inset)
370         if (isRequired("lyxgreyedout"))
371                 macros << lyxgreyedout_def;
372
373         // floats
374         getFloatDefinitions(macros);
375
376         return macros.str();
377 }
378
379
380 string const LaTeXFeatures::getBabelOptions() const
381 {
382         ostringstream tmp;
383
384         LanguageList::const_iterator it  = UsedLanguages_.begin();
385         LanguageList::const_iterator end =  UsedLanguages_.end();
386         for (; it != end; ++it)
387                 if (!(*it)->latex_options().empty())
388                         tmp << (*it)->latex_options() << '\n';
389         if (!params_.language->latex_options().empty())
390                 tmp << params_.language->latex_options() << '\n';
391
392         return tmp.str();
393 }
394
395
396 string const LaTeXFeatures::getTClassPreamble() const
397 {
398         // the text class specific preamble
399         LyXTextClass const & tclass = params_.getLyXTextClass();
400         ostringstream tcpreamble;
401
402         tcpreamble << tclass.preamble();
403
404         list<string>::const_iterator cit = usedLayouts_.begin();
405         list<string>::const_iterator end = usedLayouts_.end();
406         for (; cit != end; ++cit) {
407                 tcpreamble << tclass[*cit]->preamble();
408         }
409
410         CharStyles::iterator cs = tclass.charstyles().begin();
411         CharStyles::iterator csend = tclass.charstyles().end();
412         for (; cs != csend; ++cs) {
413                 if (isRequired(cs->name))
414                         tcpreamble << cs->preamble;
415         }
416         
417         return tcpreamble.str();
418 }
419
420
421 string const LaTeXFeatures::getLyXSGMLEntities() const
422 {
423         // Definition of entities used in the document that are LyX related.
424         ostringstream entities;
425
426         if (isRequired("lyxarrow")) {
427                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
428         }
429
430         return entities.str();
431 }
432
433
434 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
435 {
436         ostringstream sgmlpreamble;
437         string const basename = OnlyPath(fname);
438
439         FileMap::const_iterator end = IncludedFiles_.end();
440         for (FileMap::const_iterator fi = IncludedFiles_.begin();
441              fi != end; ++fi)
442                 sgmlpreamble << "\n<!ENTITY " << fi->first
443                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
444                              << MakeRelPath(fi->second, basename) << "\">";
445
446         return sgmlpreamble.str();
447 }
448
449
450 void LaTeXFeatures::showStruct() const {
451         lyxerr << "LyX needs the following commands when LaTeXing:"
452                << "\n***** Packages:" << getPackages()
453                << "\n***** Macros:" << getMacros()
454                << "\n***** Textclass stuff:" << getTClassPreamble()
455                << "\n***** done." << endl;
456 }
457
458
459 Buffer const & LaTeXFeatures::buffer() const
460 {
461         return buffer_;
462 }
463
464
465 BufferParams const & LaTeXFeatures::bufferParams() const
466 {
467         return params_;
468 }
469
470
471 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
472 {
473         FloatList const & floats = params_.getLyXTextClass().floats();
474
475         // Here we will output the code to create the needed float styles.
476         // We will try to do this as minimal as possible.
477         // \floatstyle{ruled}
478         // \newfloat{algorithm}{htbp}{loa}
479         // \floatname{algorithm}{Algorithm}
480         UsedFloats::const_iterator cit = usedFloats_.begin();
481         UsedFloats::const_iterator end = usedFloats_.end();
482         // ostringstream floats;
483         for (; cit != end; ++cit) {
484                 Floating const & fl = floats.getType((*cit));
485
486                 // For builtin floats we do nothing.
487                 if (fl.builtin()) continue;
488
489                 // We have to special case "table" and "figure"
490                 if (fl.type() == "tabular" || fl.type() == "figure") {
491                         // Output code to modify "table" or "figure"
492                         // but only if builtin == false
493                         // and that have to be true at this point in the
494                         // function.
495                         string const type = fl.type();
496                         string const placement = fl.placement();
497                         string const style = fl.style();
498                         if (!style.empty()) {
499                                 os << "\\floatstyle{" << style << "}\n"
500                                    << "\\restylefloat{" << type << "}\n";
501                         }
502                         if (!placement.empty()) {
503                                 os << "\\floatplacement{" << type << "}{"
504                                    << placement << "}\n";
505                         }
506                 } else {
507                         // The other non builtin floats.
508
509                         string const type = fl.type();
510                         string const placement = fl.placement();
511                         string const ext = fl.ext();
512                         string const within = fl.within();
513                         string const style = fl.style();
514                         string const name = fl.name();
515                         os << "\\floatstyle{" << style << "}\n"
516                            << "\\newfloat{" << type << "}{" << placement
517                            << "}{" << ext << '}';
518                         if (!within.empty())
519                                 os << '[' << within << ']';
520                         os << '\n'
521                            << "\\floatname{" << type << "}{"
522                            << name << "}\n";
523
524                         // What missing here is to code to minimalize the code
525                         // output so that the same floatstyle will not be
526                         // used several times, when the same style is still in
527                         // effect. (Lgb)
528                 }
529         }
530 }